Trama

Configuration

Review the Trama configuration surface for workers, Redis topology, queue sharding, telemetry, and deployment profiles. Start with local defaults, then move into worker scaling and Redis Cluster settings when preparing production environments.

Reference page Operators and platform teams Local to production

Start here

For local development, focus on runtime enablement, Redis/Postgres connectivity, and metrics. For production, focus on worker count, Redis topology, queue behavior, telemetry, and shard ownership settings.

Core Keys

KeyDefaultPurpose
RUNTIME
runtime.enabledtrueRun queue workers on this instance. With false the instance only serves the API (runs, callbacks, queries) and leaves execution to worker pods.
runtime.workerCount32Executions a process runs at once. Workers are coroutines that mostly wait on HTTP, so this is a concurrency limit, not a thread count; it also bounds the concurrent calls a process makes to downstream services. Default 4 before 2.2.0.
runtime.prefetchworkerCountExecutions claimed ahead of a free worker. A process holds at most workerCount + prefetch claims. Since 2.1.0.
runtime.bufferSizeignoredDeprecated since 2.1.0: claims are bounded by workerCount + prefetch.
runtime.emptyPollDelayMillis50Delay between polls of the due-work index when nothing is due.
runtime.fullSweepIntervalMillis5000How often claimers also visit every owned shard, as a safety net for the due-work index. Since 2.1.0.
runtime.livenessStallMillis120000/healthz fails after this long without consumer progress. Since 2.1.0.
runtime.maxStepsPerExecution25Maximum nodes processed per worker cycle before re-enqueue.
runtime.storeREDISREDIS or POSTGRES. Since 2.1.0 execution state is always in Postgres; REDIS only adds fast callback replay protection.
runtime.callback.baseUrl""Public base URL injected as {{runtime.callback.url}} in async task requests. Required for async tasks.
runtime.callback.hmacSecret""HMAC-SHA256 secret for signing and validating callback tokens. Required for async tasks.
runtime.callback.hmacKiddefaultKey ID embedded in the token header for future key rotation.
REDIS
redis.topologySTANDALONERedis client mode: STANDALONE or CLUSTER.
redis.urlredis://localhost:6379Connection URL used in standalone mode.
redis.commandTimeoutMillis5000Upper bound for any Redis command. While disconnected, commands fail immediately instead of queueing. Since 2.1.0.
redis.pool.*ignoredDeprecated since 2.1.0: Trama uses one multiplexed connection per process.
redis.cluster.nodes[]Seed nodes used when redis.topology=CLUSTER.
redis.queue.keyPrefixsaga:executionsPrefix for shard-aware ready and in-flight queue keys.
redis.consumer.batchSize50Messages claimed per poll cycle.
redis.consumer.processingTimeoutMillis20000In-flight claim lease. Workers renew the claims they are still processing every third of it, so it only bounds how long work claimed by a pod that died waits before being re-delivered.
redis.consumer.requeueIntervalMillisignoredDeprecated since 2.0.0: expired claims are recovered by the regular claim pass.
redis.sharding.virtualShardCount64Queue shards that pods divide by rendezvous allocation. Must be the same on every pod; it bounds how many pods can share the work. Lowering it is safe: work in removed shards is moved over automatically. Default 1024 before 2.3.0.
redis.sharding.membershipKeysaga:runtime:podsRedis ZSET tracking live worker pods.
redis.sharding.membershipTtlMillis10000Worker membership entry TTL.
redis.sharding.heartbeatIntervalMillis3000How often each worker refreshes its membership entry.
redis.sharding.refreshIntervalMillis2000How often each worker recalculates shard ownership.
redis.sharding.claimerCount4Parallel shard claimers per worker process.
DATABASE
database.hostdbPostgres host. Postgres is always required: it is the source of truth for definitions, each execution's state and resume point, step history and join barriers.
database.port5432Postgres port.
database.databasesagaPostgres database name.
database.usersagaPostgres user.
database.passwordsagaPostgres password.
database.pool.maxPoolSize10Maximum JDBC connection pool size.
database.pool.minIdle1Minimum idle JDBC connections.
database.pool.definitionCacheMaxSize1000Stored definitions cached per pod.
database.pool.definitionCacheTtlMillis5000How long a pod may keep serving a cached definition (e.g. one deleted through another pod). 0 disables the cache.
HTTP CLIENT
http.connectTimeoutMillis10000Outbound HTTP connect timeout for workflow task requests.
http.requestTimeoutMillis30000Total outbound HTTP request timeout.
http.socketTimeoutMillis30000Outbound HTTP socket read timeout.
RATE LIMIT
rateLimit.enabledtruePer-workflow breaker: after repeated worker failures (exceptions while processing), delay that workflow's executions. Executions that end FAILED by their own logic don't count (since 2.1.0). Fails open if Redis is unavailable.
rateLimit.maxFailures5Worker failures within the window before the workflow is paused.
rateLimit.windowMillis60000Sliding window duration for failure counting.
rateLimit.blockMillis60000How long a blocked execution is held before retry is allowed.
rateLimit.keyPrefixsaga:rateRedis key prefix for rate-limit counters.
RECOVERY
reconciler.enabledtrueRe-send running or sleeping executions that stopped advancing (e.g. their Redis queue item was lost), from their Postgres checkpoint. Since 2.1.0.
reconciler.staleAfterMillis120000How long past its due time an execution must be idle to be re-sent. Keep it well above the longest single node (the HTTP request timeout).
reconciler.intervalMillis30000How often the reconciler scans.
reconciler.batchSize200Executions re-sent per scan.
joinCompletionScanner.intervalMillis30000Backstop that resumes a parent whose branches all finished. Default 5 minutes before 2.1.0.
callbackTimeoutScanner.intervalMillis300000Backstop that times out callback waits whose deadline passed (bufferSeconds grace, default 120).
MAINTENANCE
maintenance.enabledtrueEnable the background partition maintenance job (Postgres only).
maintenance.partitionLookaheadMonths13How many months ahead to pre-create Postgres partitions.
maintenance.partitionStartOffsetMonths1How many months back to start partition creation.
maintenance.retentionDays15Days of execution history to retain before purging (executions, step results and step calls).
maintenance.intervalMillis3600000How often the maintenance job runs (1 hour default).
METRICS & TELEMETRY
metrics.enabledtrueExpose Prometheus metrics at /metrics.
telemetry.enabledfalseEnable OpenTelemetry span export.
telemetry.serviceNametramaService name attached to all exported spans.
telemetry.otlpEndpointhttp://localhost:4317OTLP gRPC endpoint for trace export.

Async Callback

Async task nodes pause a workflow and wait for an external system to POST to a callback URL. The three runtime.callback.* keys must be set for this to work. The runtime injects {{runtime.callback.url}} and {{runtime.callback.token}} template variables into the outbound request body, so the external service knows where to call back and which token to present.

runtime:
  callback:
    baseUrl: "https://trama.internal"   # must be reachable by downstream services
    hmacSecret: "change-me-in-production"
    hmacKid: "default"

Redis Cluster

Trama supports Redis Cluster-aware queue sharding. Ready/in-flight queue keys and rate-limit keys are written with hash tags so multi-key Lua operations stay inside one Redis slot. The due-work index is a single key.

redis:
  topology: "CLUSTER"
  cluster:
    nodes:
      - "redis://redis-cluster-0.redis:6379"
      - "redis://redis-cluster-1.redis:6379"
      - "redis://redis-cluster-2.redis:6379"
  queue:
    keyPrefix: "saga:executions"
  consumer:
    batchSize: 100
    processingTimeoutMillis: 20000
  sharding:
    podId: "${HOSTNAME}"
    virtualShardCount: 64
    membershipKey: "saga:runtime:pods"
    membershipTtlMillis: 10000
    heartbeatIntervalMillis: 3000
    refreshIntervalMillis: 2000
    claimerCount: 4

Environment Overrides

Supported overrides include:

RUNTIME_ENABLED
RUNTIME_WORKERCOUNT       # since 2.1.0
RUNTIME_PREFETCH          # since 2.1.0
RUNTIME_EMPTYPOLLDELAYMILLIS
RUNTIME_CALLBACK_BASEURL
RUNTIME_CALLBACK_HMACSECRET
RUNTIME_CALLBACK_HMACKID
METRICS_ENABLED
TELEMETRY_ENABLED
REDIS_URL
REDIS_TOPOLOGY            # STANDALONE | CLUSTER (since 2.0.1)
REDIS_CLUSTER_NODES       # comma-separated seed nodes (since 2.0.1)
REDIS_SHARDING_VIRTUALSHARDCOUNT
REDIS_COMMANDTIMEOUTMILLIS            # since 2.1.0
RECONCILER_ENABLED                    # since 2.1.0
RECONCILER_STALEAFTERMILLIS           # since 2.1.0
RECONCILER_INTERVALMILLIS             # since 2.1.0
RATELIMIT_ENABLED                     # since 2.1.0
DATABASE_HOST
DATABASE_PORT
DATABASE_DATABASE
DATABASE_USER
DATABASE_PASSWORD
DATABASE_POOL_DEFINITIONCACHETTLMILLIS

Each override can also be passed as a JVM system property with the dotted key (e.g. -Dredis.topology=CLUSTER). Any other key can be overridden with Hoplite's -Dconfig.override.<key>=<value> system properties.

Profiles

Dev profile

runtime:
  workerCount: 2
  emptyPollDelayMillis: 100
metrics:
  enabled: true
telemetry:
  enabled: false

Prod profile (split API and Workers)

In production you can run API pods separately from worker pods. An API pod (runtime.enabled: false) accepts runs and callbacks and queues them; worker pods execute them. Since 2.1.0; earlier versions answered 503 in this mode.

API deployment profile

runtime:
  enabled: false
metrics:
  enabled: true
telemetry:
  enabled: true
database:
  pool:
    maxPoolSize: 20

Worker deployment profile

runtime:
  enabled: true
  workerCount: 32
  maxStepsPerExecution: 25
redis:
  consumer:
    batchSize: 100
    processingTimeoutMillis: 20000
rateLimit:
  enabled: true
metrics:
  enabled: true
telemetry:
  enabled: true

Worker deployment profile with Redis Cluster

runtime:
  enabled: true
  workerCount: 32
redis:
  topology: "CLUSTER"
  cluster:
    nodes:
      - "redis://redis-cluster-0.redis:6379"
      - "redis://redis-cluster-1.redis:6379"
      - "redis://redis-cluster-2.redis:6379"
  consumer:
    batchSize: 100
    processingTimeoutMillis: 20000
  sharding:
    podId: "${HOSTNAME}"
    virtualShardCount: 64
    membershipKey: "saga:runtime:pods"
    membershipTtlMillis: 10000
    heartbeatIntervalMillis: 3000
    refreshIntervalMillis: 2000
    claimerCount: 4
metrics:
  enabled: true
telemetry:
  enabled: true

Scale workers horizontally by running multiple worker deployments/replicas with this same worker profile.