Zero-dependency, pure Go Aeron cluster client. No CGO. No C library.
Built for low-latency Go services that need Aeron's shared-memory transport without inheriting a C toolchain. Talks to the media driver directly over mmap'd shared memory using only the Go standard library -- no third-party Go modules, no import "C", no linker flags.
- Pure Go -- talks directly to the media driver via mmap'd shared memory (
syscall.Mmap+sync/atomic) - Zero dependencies -- only Go standard library
- Cluster client -- full Aeron cluster protocol: session connect, leader tracking, reconnection, graceful shutdown
- Aeron-idiomatic API --
Aeron,Publication,Subscription,Image,FragmentHandler,Conductor
- Go 1.26+
- A running Aeron media driver (
aeronmd)
A single import gets you both the raw pub/sub client and the cluster client:
import "github.com/andrewwormald/aergo"
// Connect to the media driver
client, err := aergo.Connect(aergo.WithDir("/dev/shm/aeron-user"))
// Create a publication
pub, err := client.AddPublication("aeron:udp?endpoint=localhost:40123", 1001)
pub.Offer([]byte("hello"))
// Create a subscription
sub, err := client.AddSubscription("aeron:udp?endpoint=localhost:40123", 1001)
sub.Poll(func(buffer []byte, header *aergo.Header) {
fmt.Println("received:", string(buffer))
}, 10)Most consumers want the cluster client rather than raw pub/sub:
cfg := aergo.DefaultClusterConfig()
cfg.AeronDir = "/dev/shm/aeron-user"
cfg.Members = []aergo.ClusterMember{{MemberId: 0, Endpoint: "localhost:10000"}}
cc, err := aergo.NewCluster(cfg)
cc.Connect()
for cc.State() != aergo.StateConnected {
cc.Poll()
}
cc.Offer([]byte("hello cluster"))aergo is a client -- it talks to a running aeronmd process via shared memory. The media driver itself is the upstream Aeron C/C++ build; this repo does not bundle a build script. Follow the upstream build instructions:
- https://github.com/aeron-io/aeron (
cppbuild/cppbuildorcmakedirectly)
Once built, launch the driver and point aergo at the same directory:
aeronmd # defaults to /dev/shm/aeron-<user>
go run ./cmd/aergo -dir /dev/shm/aeron-<user> # use the same pathsyscall.Mmap(cnc.dat)
|
package aergo (repo root, single package)
|-- AtomicBuffer, ManyToOneRingBuffer, -- pure Go shared memory protocol
| BroadcastReceiver, Conductor,
| Publication, Subscription
|
`-- Cluster, AeronCluster, ClusterConfig -- Aeron cluster protocol built on
SBE codecs, EgressListener the above (session connect,
leader tracking, reconnection)
The Aeron media driver manages shared memory regions for inter-process communication:
CnC File (cnc.dat)
├── To-Driver Buffer → ManyToOneRingBuffer (send commands)
├── To-Clients Buffer → BroadcastReceiver (receive responses)
├── Counter Values → AtomicBuffer (heartbeat, positions)
├── Counter Metadata → counter definitions
└── Error Log Buffer → AtomicBuffer (driver error reports)
Log Buffer Files (per publication/subscription)
├── Term 0, 1, 2 → TermAppender (write) / TermReader (read)
└── Metadata → tail positions, connection status
Data-plane reads and writes use sync/atomic directly on the mmap'd shared memory. Publication.Offer is fully lock-free; Subscription.Poll takes a brief sync.Mutex only to snapshot the image set published by the conductor, then iterates and reads from each term buffer lock-free.
go test ./...MIT