Configuration

Every binary is configured through environment variables. There are no config files, no flags. This page is the complete reference.

Engine

The engine binary (cmd/engine) hosts the gRPC API, the timer manager, the dispatch loop, the leader election, and the metrics server.

Networking

VariableDefaultWhat it does
ENGINE_PORT50051gRPC listen port
SCHED_METRICS_PORT9090Prometheus /metrics and /healthz listen port

Storage

VariableDefaultWhat it does
SCHED_POSTGRES_DSN(unset)Postgres connection string. Unset falls back to in-memory store.
POSTGRES_DSN(unset)Alias for SCHED_POSTGRES_DSN. The engine reads either.
REDIS_ADDR(unset)Redis address (e.g. redis:6379). Unset falls back to in-memory queue.

In-memory mode disables leader election and loses all state on restart. Use only for tests and the no-Redis fallback in local dev.

A typical Postgres DSN:

Text
postgres://sched:sched@postgres:5432/sched?sslmode=disable

For RDS or managed Postgres with TLS:

Text
postgres://user:pass@host:5432/sched?sslmode=require&pool_max_conns=20

Leader election

VariableDefaultWhat it does
SCHED_LEADER_LOCK_KEY0x53636845644c6431Postgres advisory lock key. Override per environment.

Set the same value on every engine instance in one logical cluster. Use distinct values to keep separate clusters (staging vs prod) from colliding on the same Postgres.

Shutdown

VariableDefaultWhat it does
SCHED_SHUTDOWN_GRACE_SECONDS8Seconds to drain in-flight RPCs and streams on SIGTERM

Activities longer than the grace period get their workers terminated mid-execution. The engine reclaims the un-acked task on the next reclaim cycle and a new worker re-runs it.

Observability (engine + every other binary)

These work for engine, worker, and dashboard.

VariableDefaultWhat it does
SCHED_LOG_LEVELinfodebug, info, warn, error
SCHED_LOG_FORMATtexttext or json
SCHED_OTLP_ENDPOINT(unset)OTLP/gRPC endpoint. Unset disables tracing.
SCHED_OTEL_SERVICE_NAMEper-binaryService name reported in traces

When SCHED_OTLP_ENDPOINT is unset, the engine installs a no-op tracer. There is no overhead, no failing exporter background goroutine.

Worker

The worker binary (cmd/sdk) is the demo worker; in production you build your own worker that imports the SDK. The variables below apply when you use the bundled binary as-is.

VariableDefaultWhat it does
ENGINE_ADDRESSlocalhost:50051gRPC address of the engine
TASK_QUEUEdefaultTask queue name to poll
SCHED_WORKER_STREAMINGfalseOpt in to bidi-streamed task delivery
AUTO_START_TESTfalseRegister and start demo workflows on boot

Streaming dispatch

Set SCHED_WORKER_STREAMING=true to use StreamWorkflowTasks and StreamActivityTasks instead of long-polling. The worker opens both streams in parallel and receives tasks as the engine produces them. Sub-millisecond delivery; clean shutdown when the worker exits.

The long-poll mode is the default for backwards compatibility and as a fallback when streaming has issues. Both modes coexist in the same engine; flipping the worker flag does not require an engine restart.

AUTO_START_TEST

Demo mode. The worker registers a handful of test workflows and starts them on boot, useful for kicking the tires. Do not run this in production; the workflows will collide with anything else you start and the workflows themselves are toys.

Dashboard

The dashboard binary (cmd/dashboard) serves the React SPA and proxies gRPC calls to the engine.

VariableDefaultWhat it does
DASHBOARD_PORT8080HTTP listen port
ENGINE_ADDRESSlocalhost:50051gRPC address of the engine

The dashboard does not authenticate. Put it behind a reverse proxy with auth (oauth2-proxy, Cloudflare Access, your own SSO) before exposing it publicly.

Testing

The integration test suite uses a real Postgres and a real Redis. Configure them:

VariableWhat it does
SCHED_TEST_POSTGRES_DSNPostgres DSN for integration tests
SCHED_TEST_REDIS_ADDRRedis address for integration tests

The CI workflow sets both against the Postgres 16 and Redis 7 service containers (see .github/workflows/ci.yml).

Examples

Single-engine local dev

Text
SCHED_POSTGRES_DSN=postgres://sched:sched@localhost:5432/sched?sslmode=disable
REDIS_ADDR=localhost:6379
SCHED_LOG_FORMAT=text
SCHED_LOG_LEVEL=debug

Production engine

Text
SCHED_POSTGRES_DSN=postgres://sched:****@postgres:5432/sched?sslmode=require
REDIS_ADDR=redis:6379
SCHED_LEADER_LOCK_KEY=1001
SCHED_SHUTDOWN_GRACE_SECONDS=30
SCHED_METRICS_PORT=9090
SCHED_LOG_FORMAT=json
SCHED_LOG_LEVEL=info
SCHED_OTLP_ENDPOINT=otel-collector:4317
SCHED_OTEL_SERVICE_NAME=sched-engine

Production worker

Text
ENGINE_ADDRESS=sched-engine.svc.cluster.local:50051
TASK_QUEUE=payments
SCHED_WORKER_STREAMING=true
SCHED_LOG_FORMAT=json
SCHED_LOG_LEVEL=info
SCHED_OTLP_ENDPOINT=otel-collector:4317
SCHED_OTEL_SERVICE_NAME=sched-worker-payments

What to read next