Skip to content

Embed a server

Use server.Register rather than server.New when the process already has a controls.Controller, which for an estate service it does.

srv, err := server.Register(ctx, "nats", controller, log, gonats.ServerSettings{
    InProcessOnly: true,
})
if err != nil {
    return err
}

That registers start, stop, readiness and liveness with the controller. The server is not started yet — the controller starts it, alongside everything else, in registration order. It is usable for wiring immediately, so an in-process client can be constructed from it before anything runs.

Register it first

The controller stops services in reverse registration order, so anything registered after the server stops before it. That is the order you want: consumers drain while the broker is still there to drain into.

srv, _ := server.Register(ctx, "nats", controller, log, settings)   // first
cli, _ := client.Connect(ctx, clientSettings, nil, client.InProcess(srv))

controller.Register("ingest", controls.WithStart(ingest.Start), ...)  // after

Readiness and liveness are different questions

Readiness asks whether the server is accepting connections. Liveness asks whether it is running at all.

The distinction earns its keep at startup: a server that is running but not yet accepting is starting, and restarting it would only make it start again. Collapsing the two turns a slow start into a restart loop.

Turning on JetStream

gonats.ServerSettings{
    JetStream: true,
    StoreDir:  "/var/lib/myservice/nats",
    MaxStore:  8 << 30,
}

StoreDir is required when JetStream is set, and construction fails without it. A JetStream server with no store directory writes wherever it decides to, which differs by host and survives a deployment differently on each one.

Meshing with peers

gonats.ServerSettings{
    Host:        "0.0.0.0",
    Port:        4222,
    ClusterName: "estate",
    ClusterPort: 6222,
    Routes:      []string{"nats://peer-a:6222", "nats://peer-b:6222"},
}

ClusterName is required alongside Routes — a server with no cluster name cannot mesh, and finding that out from a silent failure to form a cluster is worse than failing to construct.

Three servers, not two

JetStream replication is RAFT, so a quorum needs a majority. Two servers is not a small cluster; it is two servers that cannot agree. Replication only becomes available at three.