---
id: platform/durable-workers
title: Process durable jobs in a background worker
description: Run a downloadable Postgres job producer and worker with SKIP LOCKED claims, bounded retries, and inspectable results on Bex.
keywords: [bex, background worker, postgres, queue, SKIP LOCKED, durable jobs]
last_updated: 2026-09-23
---

Background workers have no HTTP port. Useful work has to be visible in logs or
in your datastore — not in a readiness probe. This page points at a downloadable
producer/worker that stores durable jobs and results in Postgres.

Source pin: Bex `0b2421de955618e334936ede506b502f1413cad1` (`type: worker`,
Blueprint `fromDatabase`, no health-check path on workers).

## What the sample does

The [`durable-worker`](/examples/durable-worker/README.md) example (also listed
in the [examples catalog](/examples?task=workers)):

1. Creates `jobs` and `job_results` tables
2. Submits jobs with an idempotent `submit_key`
3. Claims work with `SELECT … FOR UPDATE SKIP LOCKED` and a time-bounded lease
4. Uppercases the payload (deterministic useful work) and writes one result row
   per job
5. Returns interrupted leases to the pool; exhausts retries into an inspectable
   `failed` status

Two concurrent workers can drain the same cohort without duplicate
`job_results` rows. Completing a job requires matching `locked_by`. Database
result uniqueness is not a promise of exactly-once external side effects.

## Run locally

```bash
curl -fsSLO https://bex.co/examples/durable-worker-latest.zip
curl -fsSLO https://bex.co/examples/durable-worker-latest.zip.sha256
shasum -a 256 -c durable-worker-latest.zip.sha256
unzip durable-worker-latest.zip
cd durable-worker
npm install
npm run setup
npm run migrate
npm run seed
npm run worker &
npm run produce -- --count 5
npm run inspect
npm run teardown -- --container
```

Local setup/seed/teardown target only owned disposable Postgres (container
`eden-cms-durable-worker` on port `55433`). Runtime `worker.mjs` /
`producer.mjs` accept a reader-supplied `DATABASE_URL`, including a Bex
Postgres connection string.

## Deploy on Bex

Use the sample `render.yaml`: a `type: worker` service with
`dockerCommand: node worker.mjs` and `DATABASE_URL` from
`fromDatabase.connectionString`. Workers must not set `healthCheckPath`.
Review plans before apply — see [Background workers](./background-workers.md)
and [Blueprints](./app-resource.md).

A running Deployment does not certify queue progress. Inspect
`jobs`/`job_results` or [logs](./logging.md).

## Related

- [Background workers](./background-workers.md)
- [Postgres](./postgres.md)
- [App lifecycle](./app-lifecycle.md)
- [Rehearse a Postgres schema change](./postgres-schema-rollout.md)
