Deployment
go-saga-orchestration ships two stateless services โ the HTTP api and the gRPC engine โ as container images, plus a Helm chart attached to each release.
Container imagesโ
Published to GHCR on every release (multi-arch amd64/arm64):
ghcr.io/bugs5382/go-saga-orchestration/apighcr.io/bugs5382/go-saga-orchestration/engine
Tags: vX.Y.Z, latest, and the commit SHA.
Prerequisitesโ
Both services require, at runtime:
- A reachable RabbitMQ (
RABBITMQ_URL) โ both the api and the engine connect on startup and exit if it is unavailable. - A store:
postgres(default),redis/valkey, ormemory(single-process, dev only). postgres needsDATABASE_DSN; redis/valkey needsREDIS_URL.
Supply the connection strings through a Secret and point the chart at it:
kubectl create secret generic gosaga-conn \
--from-literal=rabbitmq-url='amqp://user:pass@rabbitmq:5672/' \
--from-literal=database-dsn='postgres://user:pass@postgres:5432/saga?sslmode=require'
Install the Helm chartโ
The chart is attached to each GitHub Release as go-saga-orchestration-<version>.tgz.
Replace <version> below with the release you want (see the
Releases page):
helm install go-saga \
https://github.com/Bugs5382/go-saga-orchestration/releases/download/v<version>/go-saga-orchestration-<version>.tgz \
--set store.type=postgres \
--set connectionSecret=gosaga-conn
Configurationโ
| Value | Default | Description |
|---|---|---|
store.type | postgres | postgres / redis / valkey / memory (โ STORE_TYPE) |
connectionSecret | "" | Secret with rabbitmq-url (required) + database-dsn or redis-url |
api.replicas / engine.replicas | 1 | Replica counts (both stateless) |
api.port | 8080 | API HTTP port (WORKFLOW_API_PORT) |
engine.grpcPort | 9090 | Engine gRPC port (WORKFLOW_ENGINE_GRPC_PORT) |
cron.dedicated | false | Run the cron dispatcher on a dedicated pod and off the main engines (see below) |
cron.replicas | 1 | Replicas for the dedicated cron pod (only when cron.dedicated) |
ingress.enabled | false | Expose the api via Ingress |
See deployments/helm/values.yaml for the full set, including probes, resources, and security context.
Cron dispatcher topologyโ
The engine's cron dispatcher polls for due cron triggers and fires them. Firing
is exactly-once across every engine pod โ each fire is claimed with a
compare-and-swap on the trigger's next_fire_at (ClaimCronFire), so even if
many pods run the loop at once, only one wins each window. Running cron on every
engine pod is therefore always safe.
A single Helm switch, cron.dedicated, picks the topology:
cron.dedicated: false(default) โ no extra pod. Every main engine pod runs the cron dispatcher (WORKFLOW_CRON_DISPATCHER=true); the CAS keeps firing single-shot. Simplest single-deployment setup.cron.dedicated: trueโ one dedicated single-replica cron pod runs the dispatcher, and it is turned off on every (scaled) main engine pod. This gives predictable scheduling, resource isolation, and one obvious cron writer while the main engines scale out purely for saga processing. The cron pod reuses the engine image, ConfigMap, and connection Secret. Enabling the dedicated pod is the only switch โ there is no separate per-engine cron flag; the chart derivesWORKFLOW_CRON_DISPATCHERfor both deployments from it.
Even with cron.dedicated: true you may raise cron.replicas above 1 for
availability โ the ClaimCronFire CAS still guarantees each window fires once,
so duplicate cron pods do not double-fire.