Single-node · In-memory · gRPC

Heads up: I ended up switching to NATS + PostgreSQL. If you need consumer groups, bare NATS won't help — you need JetStream, which requires persistence. tinybroker fills the gap when you want in-memory consumer groups with no persistence overhead. The code works and is free to use; just know why you're reaching for it.

Docker Compose

Download docker-compose.yml and run:

docker compose up -d

The compose file includes a health check and an inline config.json5 via Docker Configs so you can customise capacity and log format without building a custom image.

version: "3.9"

services:
  tinybroker:
    image: phughk/tinybroker:latest
    restart: unless-stopped
    ports:
      - "50051:50051"   # gRPC API
      - "8080:8080"     # health checks
      - "9090:9090"     # Prometheus metrics
    configs:
      - source: broker_config
        target: /config.json5
    healthcheck:
      test: ["CMD", "wget", "-qO-", "http://localhost:8080/ready"]
      interval: 10s
      timeout: 3s
      retries: 3

configs:
  broker_config:
    content: |
      {
        bind: {
          grpc:    "[::]:50051",
          health:  "[::]:8080",
          metrics: "[::]:9090",
        },
        channel: {
          command_capacity:  256,
          consumer_capacity: 256,
          event_capacity:     64,
        },
        log: { format: "json" },
      }

Kubernetes

See the k3s / Kubernetes use case for a complete Deployment + Service manifest.

Configuration reference

Place config.json5 next to the binary, or mount it at the path specified by --config.

{
  // Network bind addresses for each listener.
  bind: {
    grpc:    "[::]:50051",  // gRPC API
    health:  "[::]:8080",   // GET /health, GET /ready
    metrics: "[::]:9090",   // GET /metrics (Prometheus)
  },

  // Channel capacities control back-pressure.
  // Increase if you see "queue full" errors under high load.
  channel: {
    // Depth of the command channel: publishes, subscribes,
    // pattern changes, and topic queries all share this queue.
    command_capacity:  100,

    // Per-subscriber delivery channel depth.
    // A slow subscriber fills its channel and is evicted.
    consumer_capacity: 100,

    // Per-subscription gRPC response stream buffer.
    event_capacity:     64,
  },

  // Logging format: "text" (human-readable) or "json" (structured).
  log: { format: "text" },
}

CLI flags

All bind addresses can be overridden at startup without editing the config file:

tinybroker [OPTIONS]

  --config <PATH>         Path to config.json5 [default: config.json5]
  --grpc-bind <ADDR>      Override bind.grpc
  --health-bind <ADDR>    Override bind.health
  --metrics-bind <ADDR>   Override bind.metrics

Environment variables

Set RUST_LOG to control log verbosity:

RUST_LOG=info          # default: info-level logs
RUST_LOG=debug         # verbose: includes routing decisions
RUST_LOG=tinybroker=trace  # maximum verbosity for tinybroker module only

Prometheus metrics

MetricTypeDescription
tinybroker_grpc_connections_totalCounterTotal accepted TCP connections
tinybroker_grpc_calls_initiated_totalCountergRPC calls by method (method label)
tinybroker_subscriptions_activeGaugeCurrently active subscribe streams
tinybroker_pattern_subscriptions_activeGaugeActive topic patterns across all subscriptions
tinybroker_topics_totalGaugeNumber of distinct topics ever published to
tinybroker_messages_published_totalCounterMessages accepted by the routing core
tinybroker_messages_delivered_totalCounterIndividual subscriber deliveries
tinybroker_consumers_evicted_totalCounterSubscribers evicted due to a full delivery channel

All metrics carry a session label set to a UUID generated on startup, so Prometheus time series from different broker instances are always distinct.

Health endpoints

GET /health returns 200 OK immediately — used for liveness probes.

GET /ready returns 200 OK once the gRPC listener is bound — used for readiness probes.