Troubleshooting

Pods fail to start: "missing stafett.pgqueuer"

missing stafett.pgqueuer, stafett.pgqueuer_log; run either image with `setup` against this database first

The schema is not installed. Run docker run <image> setup with either image, or let the chart's init container do it. If the init container itself fails, read its log:

kubectl -n stafett logs deploy/stafett-worker-enqueue -c setup

A permission error there means the role in DATABASE_URL can neither create schema stafett nor owns it. See Configuration.

Jobs are slow to start, or only start every few seconds

deliver hears about new jobs through Postgres LISTEN, and polls every 5 seconds as a fallback. A retry that starts up to 5 seconds after its backoff ends is expected; waits under 5 seconds often stretch to about 5.

If every new job waits up to 5 seconds, LISTEN is not reaching deliver.

A transaction pooler between Stafett and Postgres (PgBouncer in transaction mode, a managed provider's pooled port) breaks LISTEN, and can break Stafett's queries outright. Use the direct connection string. Pooled connections are not supported.

A job is dead

List dead jobs with pgq failed, then read why one failed with the query in Operations.

Reason Means Do
HTTP 4xx The destination refused the request. Fix the URL, auth headers, or payload. Replaying the same job usually fails again.
HTTP 3xx The destination redirected. Stafett does not follow redirects. Enqueue the final URL.
HTTP 5xx, HTTP 429 Still failing on the last attempt. Replay once the destination recovers, or raise the attempt budget.
timeout The connect, a read, or a write took longer than its timeout on the last attempt. Check the destination's latency. The destination may have processed it.
connect error Any other transport failure on the last attempt: DNS, TCP, TLS, or a connection dropped mid-request. Check name resolution, egress rules, proxy settings, and certificates from the worker pod. If the connection dropped after sending, the destination may have processed it.
unsafe url STAFETT_BLOCK_PRIVATE_URLS is on and the host is private, or did not resolve. Turn the setting off for internal destinations, or fix DNS.
unknown envelope version A newer Stafett wrote the job, and an older deliver read it. Finish the upgrade, then replay.

The receiver rejects the signature

The same job arrived twice

Expected occasionally: delivery is at-least-once. A timeout, a deliver pod that stopped mid-attempt, or a replay can each send a job again. Dedupe on webhook-id, or, with signing off, on an id header of your own.

Jobs stay queued and nothing is delivered

deliver's delivery loop stops when it loses its database connection, for example when Postgres restarts or fails over. It does not reconnect by itself, and it logs the error (connection is closed) only when the process exits. Its /healthz answers 503 meanwhile.

enqueue keeps accepting jobs meanwhile, so nothing is lost: they are delivered once deliver is running again.

pgq shows nothing

Set PGQUEUER_SCHEMA=stafett and PGDSN. Without the schema, pgq uses the connection's search_path, usually schema public. See Operations.

POST /enqueue answers 503

enqueue cannot reach Postgres. Right after a database restart or failover, the first requests can also answer 503 while enqueue replaces its closed connections. Nothing was written, with one rare exception covered in the API reference: retry with a Stafett-Dedupe-Key.