Skip to content

Getting started

By the end of this you will have a NATS server running inside your program, a client connected to it without touching the network, and a message going from one to the other.

Nothing needs installing. No broker, no container, no port.

Install

go get gitlab.com/phpboyscout/go/nats

The whole thing

package main

import (
    "context"
    "fmt"
    "log/slog"
    "time"

    "github.com/nats-io/nats.go"

    gonats "gitlab.com/phpboyscout/go/nats"
    "gitlab.com/phpboyscout/go/nats/client"
    "gitlab.com/phpboyscout/go/nats/server"
)

func main() {
    ctx := context.Background()
    log := slog.Default()

    // A server with no listener at all — not even loopback.
    srv, err := server.New(ctx, gonats.ServerSettings{InProcessOnly: true})
    if err != nil {
        panic(err)
    }

    if err := server.Start(log, srv)(ctx); err != nil {
        panic(err)
    }
    defer server.Stop(log, srv)(ctx)

    // A client that reaches it through memory rather than a socket.
    cli, err := client.Connect(ctx, gonats.ClientSettings{Name: "tutorial"}, nil,
        client.InProcess(srv))
    if err != nil {
        panic(err)
    }
    defer cli.Close()

    got := make(chan string, 1)

    if _, err := cli.Subscribe("greetings", func(m *nats.Msg) {
        got <- string(m.Data)
    }); err != nil {
        panic(err)
    }

    if err := cli.Conn().Publish("greetings", []byte("hello")); err != nil {
        panic(err)
    }

    select {
    case msg := <-got:
        fmt.Println("received:", msg)
    case <-time.After(time.Second):
        fmt.Println("nothing arrived")
    }
}

Run it and you get received: hello.

What just happened

server.New built a real NATS server — the same one you would deploy standalone — and InProcessOnly told it not to open a listener. server.Start ran it and waited for it to accept connections, so a server that never becomes ready fails here rather than at your first publish.

client.InProcess(srv) is the interesting part. Instead of dialling an address, the client took an in-memory connection from the server. There is no TCP involved, not even a loopback hop.

cli.Subscribe did one thing beyond the underlying library: it bounded the subscription's queue. Left alone, NATS allows 500,000 pending messages per subscription, which is a limit in the sense that the heat death of the universe is a deadline.

Next