Configuration
Everything worker.config.ts accepts.
worker.config.ts is the single source of truth for a worker. The CLI loads
it for dev, build, and start; pass --config <path> to use a different
file.
import { defineConfig, postgresAdapter } from '@openqueue/sdk';
export default defineConfig({
namespace: 'my-app',
dirs: ['./worker'],
exclude: ['**/*.test.ts'],
redis: {
url: process.env.REDIS_URL!,
},
concurrency: {
global: 8,
queues: { exports: 2 },
},
workbench: {
enabled: true,
title: 'Jobs',
basePath: '/workbench',
},
});Reference
| Field | Description |
|---|---|
namespace | Prefix for every key this worker touches. Lets multiple apps share one backend. |
dirs | Directories scanned for exported task() definitions. |
tasks | Explicit task modules ({ module, export? }) instead of — or alongside — directory scanning. |
exclude | Glob patterns removed from discovery (tests, fixtures). |
redis.url | Redis connection string. Sugar for a BullMQ world; XOR with world. |
redis.bullPrefix | Override the BullMQ key prefix. |
world | A world factory (e.g. worldPostgres({ url })) — the non-BullMQ path. XOR with redis. When set, the world owns durable state, so storage is not accepted. |
storage | A QueueStorage — use postgresAdapter to persist run history alongside the redis transport. |
drains | Sinks for run lifecycle events; consoleDrain() ships in the box, composeDrains() combines several. |
retention | Age-based pruning of durable run history — { completed: 30, failed: 90, logs: 30 } days by default, false keeps a category forever. See Retention. |
concurrency.global | Worker-wide cap on parallel jobs. |
concurrency.queues | Per-queue caps, by queue name. |
api.token | Bearer token(s) for the /openqueue/v1 control API. Sugar for a leading apiKey() strategy. Unset = open in dev, 401 in production. |
api.auth | Ordered AuthStrategy walk for the control API. Empty array = always 401 (fail-closed). |
metrics | Toggle metric collection and key prefix. |
workbench | Dashboard options — see below. |
lifecycle | onReady / onShutdown hooks run in the worker process — on both openqueue dev and the built artifact. Each receives the runtime; enqueue with runtime.trigger(id, input, { jobId }). See below. |
build | outDir, extraFiles, external for openqueue build. |
Lifecycle hooks
Run code inside the worker process itself, on both openqueue dev and the built
artifact. The canonical use is post-deploy convergence: the worker is the only
process that observes "a new build just booted", and it already holds a runtime
that can enqueue.
export default defineConfig({
lifecycle: {
onReady: async (runtime) => {
await runtime.trigger(
'release',
{ release: BUILD_ID },
{ jobId: `release:${BUILD_ID}` },
);
},
},
});| Field | Description |
|---|---|
onReady | Runs once every consumer is started, so a job enqueued here is immediately consumable by this worker. |
onShutdown | Runs on shutdown after /ready starts failing but before consumers drain, so the runtime is still live enough to enqueue. |
Both hooks run on every replica, and a rollout boots several. When the effect
must happen once per cluster, pass a stable jobId — release:${BUILD_ID} above
— so concurrent boots collapse to a single job.
Neither hook can take the process down. A throwing hook is logged and the boot
(or drain) continues. So is a hook still running after 10 seconds: the worker
stops waiting and carries on, and the hook keeps running detached. That budget is
sized for an enqueue, which is what these hooks are for — do the actual work in
the job you trigger, not in the hook, or a slow onReady will hold the port shut
and a slow onShutdown will eat the termination grace period.
Workbench options
| Field | Description |
|---|---|
enabled | Serve the dashboard from this worker. |
title | Name shown in the dashboard chrome. |
basePath | Mount path, for example /workbench. |
readonly | Disable mutating actions (retry, enqueue, pause). |
auth | { username, password } for basic auth, or an ordered AuthStrategy walk. Unset = dashboard open. |
tagFields | Payload field names that Workbench can extract as filterable tags. |
Persistent run history
Redis keeps recent state; Postgres keeps the paper trail. Wire the Drizzle adapter to persist runs, schedules, and alerts:
import { defineConfig, postgresAdapter } from '@openqueue/sdk';
import { db } from './src/db';
import { queueSchema } from './src/queue-schema';
export default defineConfig({
namespace: 'my-app',
dirs: ['./worker'],
redis: { url: process.env.REDIS_URL! },
storage: postgresAdapter({ db, schema: queueSchema }),
});See Persistence for the table definitions, how to generate the Drizzle migrations, and retention patterns.