@absolutejs/queue-postgres

中文文档
0.1.9发布于 2026/10/26Apache-2.0TypeScriptES Module构建来源已验证近 30 天下载 2524

Postgres (Drizzle) storage adapter for @absolutejs/queue — postgres.js + Neon serverless

原始使用文档
文档目录9 节
  1. Install
  2. Usage with postgres.js
  3. Usage with Neon ( @neondatabase/serverless )
  4. Usage with any other Drizzle Postgres adapter
  5. Migrations
  6. How claiming works
  7. License
  8. Atomic claim fencing
  9. Mixed worker versions

@absolutejs/queue-postgres

Postgres storage adapter for @absolutejs/queue, built on Drizzle. The production JobStore: durable, with atomic multi-worker claiming via FOR UPDATE SKIP LOCKED. Ships convenience factories for both postgres.js and Neon's WebSocket driver (@neondatabase/serverless); the underlying buildPostgresJobStore accepts any Drizzle Postgres database, so other drivers (including Bun SQL and node-postgres) work too. Its portable JSONB encoding preserves payload objects across all supported drivers.

Install

# pick your driver
bun add @absolutejs/queue @absolutejs/queue-postgres drizzle-orm postgres
# …or
bun add @absolutejs/queue @absolutejs/queue-postgres drizzle-orm @neondatabase/serverless

postgres and @neondatabase/serverless are optional peer deps — install whichever one you'll use.

Usage with postgres.js

import { createPostgresJobStore } from '@absolutejs/queue-postgres/postgres';
import { createJobRegistry, defineJobs, queue, t } from '@absolutejs/queue';
import postgres from 'postgres';

const jobs = defineJobs({
    'email.send': t.Object({ to: t.String(), subject: t.String() })
});
const registry = createJobRegistry(jobs).on(
    'email.send',
    async ({ to, subject }) => {}
);

// Share your app's existing postgres.js client (one pool)…
const client = postgres(process.env.DATABASE_URL, { prepare: false });
const store = createPostgresJobStore({ client, jobs });

// …or let the adapter open its own connection:
// const store = createPostgresJobStore({ connectionString: url, jobs });

app.use(queue({ registry, store }));

Usage with Neon (@neondatabase/serverless)

createNeonJobStore mirrors createPostgresJobStore but uses Neon's WebSocket Pool. Important: the queue's claimDue opens a transaction and selects with FOR UPDATE SKIP LOCKED. Neon's HTTP driver (drizzle-orm/neon-http) is single-statement and can't do row-level locks — use the WebSocket Pool driver here. Your app's other code can keep using the HTTP driver; they're independent.

import {
    createNeonJobStore,
    neonConfig
} from '@absolutejs/queue-postgres/neon';
import { createJobRegistry, defineJobs, queue, t } from '@absolutejs/queue';
import { Pool } from '@neondatabase/serverless';

// Bun ships a global WebSocket; for node, polyfill once:
//   import ws from 'ws'; neonConfig.webSocketConstructor = ws;

const jobs = defineJobs({
    'email.send': t.Object({ to: t.String(), subject: t.String() })
});

// Share an existing Neon Pool…
const pool = new Pool({ connectionString: process.env.DATABASE_URL });
const store = createNeonJobStore({ jobs, pool });

// …or let the adapter open its own:
// const store = createNeonJobStore({ connectionString: url, jobs });

Usage with any other Drizzle Postgres adapter

Both factories are thin wrappers around buildPostgresJobStore(db, jobs), which accepts any PgDatabase<any, any, any> from Drizzle. If you use drizzle-orm/node-postgres, build the db yourself and pass it in:

import { buildPostgresJobStore, queueSchema } from '@absolutejs/queue-postgres/drizzle';
import { drizzle } from 'drizzle-orm/node-postgres';
import { Pool } from 'pg';

const pool = new Pool({ connectionString: process.env.DATABASE_URL });
const db = drizzle(pool, { schema: queueSchema });
const store = buildPostgresJobStore(db, jobs);

Migrations

Add the table to your Drizzle schema so it's included in migrations:

export { queueJobsTable } from '@absolutejs/queue-postgres/drizzle';

Then drizzle-kit generate / push as usual.

How claiming works

claimDue runs inside a transaction:

SELECT … FROM queue_jobs
WHERE status = 'pending' AND run_at <= $now
ORDER BY run_at LIMIT $n
FOR UPDATE SKIP LOCKED;        -- concurrent workers skip locked rows
-- then UPDATE those ids → status='claimed'

This guarantees a job is handed to exactly one worker even with many workers polling. Crashed workers are recovered by reapStuck (lease expiry → back to pending).

License

Apache-2.0 — see LICENSE.

Atomic claim fencing

The adapter now assigns claim_token with each claim and implements completeClaim / failClaim as conditional updates on job ID, token and status = 'claimed'. An expired, canceled or superseded attempt returns false without changing the current job. Updated queue workers use this capability automatically; requireClaimFencing: true refuses an incompatible store.

Apply this additive migration before starting the updated adapter (or generate it from the exported queueJobsTable with your application's migration tool):

ALTER TABLE queue_jobs ADD COLUMN IF NOT EXISTS claim_token text;

Drain older workers during rollout. Older binaries still perform unfenced updates and cannot provide this guarantee. Claim fencing protects the queue row; handlers must separately fence application writes and external side effects.

Lease expiry consumes one attempt. Reaping moves an exhausted job to dead with a lease-expiry error, so repeated worker death cannot bypass maxAttempts.

The /drizzle entry point (0.1.8+) does not load the optional postgres or Neon connection factories. Use it with Bun SQL or an existing Drizzle connection, including schema generation. Existing root exports remain compatible.

Mixed worker versions

With queue 0.8.4, enable requireKindFiltering: true on workers. Claims are restricted to both the adapter's job definition and the worker's registered handlers before the database applies its claim limit. Empty handler sets claim nothing. Upgrade every worker attached to a shared table before producing new job kinds; an older, unfiltered worker can still claim and reject those jobs.

版本与发布记录

@absolutejs/queue-postgres 共发布 17 个版本,首次发布于 2026/05/23;过去 12 个月发布了 17 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
0.1.9latest2026/10/2612 天前
0.1.82026/09/241 个月前
0.1.72026/09/161 个月前
0.1.62026/09/161 个月前
0.1.52026/08/222 个月前
0.1.42026/07/253 个月前

关于 @absolutejs/queue-postgres 的常见问题

@absolutejs/queue-postgres 是什么?

Postgres (Drizzle) storage adapter for @absolutejs/queue — postgres.js + Neon serverless

如何安装 @absolutejs/queue-postgres?

在项目目录运行 npm install @absolutejs/queue-postgres,或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖:drizzle-orm(>=1.0.0-rc.4 <2)、@absolutejs/queue(>=0.8.4 <0.11.0)。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖,Yarn 需要手动安装。

@absolutejs/queue-postgres 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@absolutejs/queue-postgres 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@absolutejs/queue-postgres 可以商用吗?

@absolutejs/queue-postgres 使用 Apache-2.0 许可。宽松许可:允许商业使用、修改和再分发,并附带明确的专利授权;分发时需保留许可与 NOTICE 文件,修改过的文件要注明改动。以上为概括,不构成法律意见,请以许可原文为准。

@absolutejs/queue-postgres 的下载量有多少?

根据 npm 官方下载统计,@absolutejs/queue-postgres 在 2026/10/05 – 2026/11/03 这 30 天内被下载 2,524 次,日均约 84 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@absolutejs/queue-postgres 还在维护吗?

最新版本 0.1.9 发布于 2026/10/26(12 天前);至今共发布 17 个版本,其中过去 12 个月发布了 17 个;首次发布于 2026/05/23。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。