Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Deployment

How to run parsec serve in something resembling production. The single-node story is the default; the multi-node story attaches a Redis backend.

parsec serve \
  --addr :8000 \
  --state-dir /var/lib/parsec \
  --keyring-poll 5s

Topology: single node

The simplest deployment is one Parsec process with an in-memory channel registry and a file-backed keyring. Centrifuge holds tens of thousands of concurrent websockets per core — single-node carries a lot of load.

Topology: clustered

Point Options.RedisClient (or the YAML redis.addr field) at a shared Redis and the broker, channel registry, keyring, DLQ, and rate limiter all switch to their Redis-backed implementations. Multiple Parsec nodes then share the same truth about open channels, keys, and sink failures. See key rotation for the rotation walkthrough.

Required state

PathWhatSurvives restart?
<state-dir>/keyring.jsonHMAC signing keysYes
In-memory channel mapOpen channels, private recordsNo
In-memory subscriber setLive websocket connectionsNo

The manifest reports "persistence": "in-memory" so clients can discover the stance without reading docs. The contract: a restart wipes every channel, every subscriber must reconnect, every private channel must be re-created with fresh tokens.

If that is a problem for your use case, Parsec is the wrong primitive — use a real durable queue.

--state-dir

Always pass it in production. Without --state-dir, the keyring is ephemeral and every restart mints a new bootstrap token under a brand new active key. Existing browser clients can no longer refresh and must re-authenticate. With --state-dir, the ring survives the restart and active sessions tolerate a quick bounce.

The directory is created with mode 0700; the keyring file with mode 0600. Both are owned by the running uid. Mount your state volume so the uid is consistent across restarts.

Environment variables

The CLI reads these at boot. The library does not — it takes typed values via Options.

VariableDefaultNotes
PARSEC_STATE_DIR“”Same as --state-dir.
PARSEC_MGMT_SUBJECToperatorSubject claim on the bootstrap mgmt token.
PARSEC_MGMT_TTL24hBootstrap mgmt TTL.
PARSEC_KEYRING_POLL5smtime-poll interval. 0 disables polling.
PARSEC_NO_AUTHunsetDangerous; disables the bearer middleware. Dev only.
PARSEC_SERVERhttp://localhost:8000Default --server for the client subcommands.
PARSEC_TOKEN“”Mgmt bearer for the client subcommands.

Capturing the bootstrap token

parsec serve prints the bootstrap mgmt token to STDERR exactly once. A typical systemd unit captures it like this:

[Service]
ExecStart=/usr/local/bin/parsec serve --addr :8000 --state-dir /var/lib/parsec
StandardError=append:/var/log/parsec/boot.log

Then grep the log:

grep "bootstrap mgmt token" /var/log/parsec/boot.log

If you persist the keyring, the same token continues to work across restarts — fetch it once, store it in your secret manager, move on.

Health and observability

EndpointPurpose
/healthzLiveness probe. Returns 200 once node.Run has succeeded.
/manifestDescriptor envelope — surfaces, sinks, version.

Centrifuge’s own metrics are exposed under broker.Node().Metrics(...); mount them on your own /metrics handler if you want Prometheus.

Upgrades

A restart kills channel state. The supported upgrade procedure:

  1. Drain or accept the disruption (browsers reconnect; private channels need fresh tokens).
  2. systemctl restart parsec (or your orchestrator’s equivalent).
  3. The new process loads the same keyring.json; active operator bearers continue to verify.

If you cannot tolerate the disconnect window, queue a maintenance banner on public:<app>.broadcast.maintenance and run during a quiet period.

See also