Architecture
Each worker pool claims jobs from PostgreSQL. There is no broker and no leader. Worker capacity scales with process count.
The lifecycle under transactionalWorkerConfig:
- Claim: The dispatcher claims visible jobs in per-group order, increments each attempt count, and hides each job for its lease. The same statement applies admission: a job with an empty rate-limit bucket is parked until its bucket refills, and a job whose concurrency key is at its limit is skipped. A heartbeat extends the lease while the handler runs.
- Run: The handler runs in a transaction. Its database work, its stored result, and the ack commit together.
- Success: The transaction commits.
- Failure: The transaction rolls back. A second transaction retries the job with backoff or moves it to the dead-letter queue (DLQ).
- Reclaim: Another worker claimed the job after its lease expired. The heartbeat or the ack throws and the worker drops the job.
Admission limits apply to every worker pool in every process and to REST API clients.
Delivery is at least once. Non-transactional side effects must be idempotent.
With manualWorkerConfig and batchedWorkerConfig, step 2 has no
transaction and the handler finalizes each job through callbacks.
Group Ordering
A group key admits one job or batch at a time. Different groups run concurrently.
- Same group key: Insertion order within priority. A retrying job stays first until it succeeds or moves to the DLQ. A ready job runs before a delayed job. The group waits through a job's backoff or rate-limit delay.
- No group key: Any free worker, concurrently.