Skip to content

Configuration

rdq configuration comes in three layers: process environment (how rdq-server boots and reaches storage), server config (platform-operator settings a queue owner can’t touch — the auth token file and callback allowlist), and per-queue policy (how each queue is retried, leased, classified, and called back). The per-queue schema is shared by both SDKs and the server, seeded by a boot YAML file and live-tunable through the admin API.

These are read directly by the rdq-server binary at startup.

NameTypeDefaultDescription
RDQ_DSNstring(required)PostgreSQL DSN, e.g. postgres://user:pass@host/db. The server refuses to start without it.
RDQ_ADDRstring:8080TCP listen address for the REST API and health probes.

On start, rdq-server applies schema migrations and refuses to run against a schema version it does not understand. Secrets referenced by callback auth are resolved from the environment via the env: scheme — e.g. a queue’s secret_ref: env:PAYMENTS_CB_TOKEN dereferences $PAYMENTS_CB_TOKEN at config load (a missing/empty variable fails fast, so a callback is never dispatched with a blank credential).

The following are documented design surfaces; the values are the intended defaults, presented here as design — not all are exposed as flags/vars in the current build.

NameTypeDefaultDescription
gRPC listen addressstring:9090 (design)gRPC intake port. gRPC intake is post-v1; v1 ships REST only.
TLS cert / keypath(none)TLS for intake. In v1, terminate TLS at a proxy/load balancer; native TLS is a documented design surface.
Graceful-drain timeoutduration15sOn SIGTERM the server stops claiming, finishes in-flight work within its lease, then exits.

Loaded from the server’s config source (design 03 §5), these settings are outside any queue owner’s reach — the SSRF and authn boundary.

KeyTypeDefaultDescription
tokens_pathstring(empty)Path to the static bearer-token file mapping token → principal + per-queue×role grants. Empty leaves the /v1 auth boundary open (dev/embedded mode only).
callback_allowlistlist of strings(empty = deny-all)Permitted callback base URLs (scheme://host[:port][/prefix] or bare host[:port]). A queue’s callback URL is delivered only if it matches. Empty means no callback URL is permitted until an operator opts a target in. Host match is exact, case-insensitive, with no subdomain wildcard.

The queue-config document is strict: unknown keys are rejected at load or on an admin write — a typo fails fast at boot, never at 3am. A top-level defaults block applies to every queue; each queue overrides it by per-key deep-merge. In YAML, durations carry units (500ms, 1s, 10m, 24h), sizes carry binary units (KiB, MiB, GiB), and rates read as count/period (100/s). The admin API speaks the same schema as JSON, where durations are integer milliseconds and sizes integer bytes.

The values in the tables below are the illustrative defaults from the shipped example defaults block. rdq validates bounds (shown as rules) but does not hard-code these numbers — the effective value is whatever your defaults/queue config sets.

delay(n) = min(initial_backoff × multiplier^(n-1), max_backoff) × (1 ± jitter).

NameTypeExampleDescription / rule
max_attemptsint5Attempts before dead-lettering. Must be ≥ 1.
initial_backoffduration1sFirst retry delay. Must be > 0.
backoff_multiplierfloat2.0Growth factor (1.0 = linear). Must be ≥ 1.0.
max_backoffduration10mDelay ceiling. Must be > 0.
jitterfloat0.2Randomization fraction in [0, 1].
NameTypeExampleDescription / rule
leaseduration60sVisibility timeout on a claim; an expired lease makes the task reclaimable. Must be > 0.
handler_timeoutduration45sMax handler runtime. Must be > 0 and lease.
heartbeatboolfalseExtend the lease for long handlers rather than letting it expire.
NameTypeExampleDescription / rule
max_payload_sizesize1MiBPer-queue payload cap; oversized submits get 413 PAYLOAD_TOO_LARGE. Must be > 0.
ttl_succeededduration24hHow long succeeded tasks are retained before purge. Must be ≥ 0.
NameTypeExampleDescription / rule
batch_sizeint32Tasks claimed per ClaimDue round-trip. Must be ≥ 1.
poll_intervalduration500msDelay between claim polls when idle. Must be > 0.
concurrencyint8Handlers run concurrently per instance. Must be ≥ 1.
rate_limitrate100/sPer-instance token bucket; global rate across N instances is N × rate_limit. Omit for unlimited.

classification — error → outcome globs

Section titled “classification — error → outcome globs”
NameTypeExampleDescription
retryablelist of globs["java.net.*", "TIMEOUT"]Error types treated as retryable.
permanentlist of globs["*.ValidationException"]Error types that skip straight to the DLQ.

Code classifiers and OutcomeMappers take precedence; this glob layer is the only one expressible in YAML. See the outcome contract.

NameTypeExampleDescription
handler.version_mismatchenumdead-letterrun-latest or dead-letter when a task’s handler version differs from the registered one.
sync_retry.attemptsint2In-process retries before durable enqueue (embedded SDK submit path only). Must be ≥ 0.
sync_retry.backoffduration100msDelay between sync-retry attempts. Must be ≥ 0.

Ignored by the embedded SDK. Registering a callback = writing this block via the admin API; the url must match the server callback_allowlist.

NameTypeExampleDescription / rule
protocolenumhttphttp (v1) or grpc (accepted by the schema; transport is post-v1).
urlstringhttps://payments.internal/rdq/chargeAbsolute callback URL. Required when a callback is configured.
timeoutduration30sPer-call timeout; a timeout is a retryable TIMEOUT failure. Must be > 0 and ≤ handler_timeout.
auth.typeenumbearernone, bearer, or header.
auth.secret_refstringenv:PAYMENTS_CB_TOKENIndirection to a secret; v1 supports the env: scheme only. Required for bearer/header.
response_mapping.retryable_statuslist[408, 429, "5xx"]Status codes/classes classified retryable, overriding the defaults.
response_mapping.permanent_statuslist["4xx"]Status codes/classes classified permanent.
config_version: 1
defaults:
retry:
max_attempts: 5
initial_backoff: 1s
backoff_multiplier: 2.0
max_backoff: 10m
jitter: 0.2
execution:
lease: 60s
handler_timeout: 45s
limits:
max_payload_size: 1MiB
ttl_succeeded: 24h
worker:
batch_size: 32
poll_interval: 500ms
concurrency: 8
rate_limit: 100/s
queues:
payments.charge:
retry:
max_attempts: 8
initial_backoff: 2s
classification:
retryable: ["java.net.*", "TIMEOUT"]
permanent: ["*.ValidationException"]
callback:
protocol: http
url: https://payments.internal/rdq/charge
timeout: 30s
auth:
type: bearer
secret_ref: env:PAYMENTS_CB_TOKEN
response_mapping:
retryable_status: [408, 429, "5xx"]
permanent_status: ["4xx"]