@cisstech/nestjs-pg-pubsub

中文文档
1.15.2发布于 2026/10/29MITTypeScriptCommonJS构建来源已验证近 30 天下载 5828

A NestJS module to provide PostgreSQL PubSub

原始使用文档
文档目录10 节
  1. What It Does
  2. Why This Exists
  3. Key Properties
  4. Installation
  5. Quick Start
  6. How It Works
  7. Important Constraints
  8. Configuration
  9. Documentation
  10. License

@cisstech/nestjs-pg-pubsub

A NestJS module for real-time PostgreSQL change data capture using triggers and a persistent queue.

CI codecov codefactor GitHub Tag npm package NPM downloads licence code style: prettier

What It Does

PostgreSQL triggers detect INSERTs, UPDATEs and DELETEs on your tables. Changes are persisted in a queue table, then pulled and dispatched to typed NestJS listeners. No polling-only design, no lost messages, no external broker.

Diagram

Why This Exists

PostgreSQL's LISTEN/NOTIFY is great for real-time but unreliable: notifications are fire-and-forget, lost during disconnects, and have a payload size limit. This library wraps it with a durable queue so you get both reactivity and guaranteed delivery.

Key Properties

  • Durable: changes are persisted in a SQL table before notification, surviving crashes and restarts
  • Reactive: LISTEN/NOTIFY triggers immediate processing, with a fallback poller as safety net
  • Ordered: messages are processed by ID, in batches, with SELECT FOR UPDATE SKIP LOCKED
  • Retry with backoff: failed messages are retried with exponential backoff ($2^{n}$ minutes)
  • Backpressure: concurrent notifications are coalesced so that at most one pull cycle runs at a time
  • Isolated pool: uses its own pg.Pool, independent of TypeORM, to avoid pool contention
  • Zero-downtime DDL: triggers are fingerprinted (MD5) and only recreated when config changes

Installation

yarn add @cisstech/nestjs-pg-pubsub pg

Supports NestJS v10+ and v11+.

Quick Start

// app.module.ts
@Module({
  imports: [
    TypeOrmModule.forRoot({
      /* ... */
    }),
    PgPubSubModule.forRoot({
      databaseUrl: process.env.DATABASE_URL,
    }),
  ],
  providers: [UserChangeListener],
})
export class AppModule {}
// user-change.listener.ts
@Injectable()
@RegisterPgTableChangeListener(User)
export class UserChangeListener implements PgTableChangeListener<User> {
  async process(changes: PgTableChanges<User>, ctx: PgTableChangeContext): Promise<void> {
    for (const insert of changes.INSERT) {
      console.log(`New user: ${insert.data.email}`)
    }

    for (const update of changes.UPDATE) {
      console.log(`Updated fields: ${update.data.updatedFields.join(', ')}`)
    }
  }
}

That's it. The library auto-creates triggers, the queue table, and starts listening.

How It Works

  1. A PostgreSQL trigger fires on table change and inserts a row into pg_pubsub_queue
  2. The trigger sends a NOTIFY with the channel name
  3. The library receives the notification and pulls pending messages from the queue
  4. Messages are dispatched to the matching @RegisterPgTableChangeListener classes
  5. Processed messages are marked as such; failed ones are retried with exponential backoff
  6. A background poller runs every 60s as a safety net for missed notifications

Important Constraints

  • Listeners must be fast. A slow listener delays the entire batch for that table. Offload heavy work to a queue (Bull, etc.) and just enqueue from the listener.
  • Use TransactionAdapter for transactional writes. If a listener needs to write to the DB inside a transaction, configure a transactionAdapter and mark the listener with @RegisterPgTableChangeListener(Entity, { transactional: true }). The library wraps the listener call in the adapter, passing an opaque transaction token via ctx.transaction. Without the adapter, use ctx.onError to signal failures.

Configuration

All options are optional except databaseUrl. See the full configuration reference for details.

Key tuning knobs:

OptionDefaultWhat it controls
queue.batchSize100Max messages fetched per pull cycle
queue.drainInterval50msPause between drain loop iterations (DB breathing room)
queue.processingTimeout5minAfter this, a processing message is considered orphaned and retried
queue.concurrency5Max listeners executing in parallel per batch
queue.awaitInitialPulltrueWhether startup waits for the initial pull to drain the queue
transactionAdapter-ORM-agnostic adapter for wrapping listeners in transactions
pool.max5Connections in the dedicated pg-pubsub pool

Documentation

Full documentation: https://cisstech.github.io/nestkit/docs/nestjs-pg-pubsub/getting-started

License

MIT © Mamadou Cisse

版本与发布记录

@cisstech/nestjs-pg-pubsub 共发布 15 个版本,首次发布于 2025/03/14;过去 12 个月发布了 9 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
1.15.2latest2026/10/2911 天前
1.15.12026/09/281 个月前
1.15.02026/03/267 个月前
1.14.12026/03/267 个月前
1.14.02026/02/198 个月前
1.13.12026/01/0810 个月前

关于 @cisstech/nestjs-pg-pubsub 的常见问题

@cisstech/nestjs-pg-pubsub 是什么?

A NestJS module to provide PostgreSQL PubSub

如何安装 @cisstech/nestjs-pg-pubsub?

在项目目录运行 npm install @cisstech/nestjs-pg-pubsub,或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖:pg(^8.x)、typeorm(^0.3.x)、pg-listen(^1.x)、@nestjs/core(^10.x || ^11.x)、@nestjs/common(^10.x || ^11.x)、@golevelup/nestjs-discovery(^4.x || ^5.x)。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖,Yarn 需要手动安装。

@cisstech/nestjs-pg-pubsub 支持 TypeScript 吗?

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

@cisstech/nestjs-pg-pubsub 支持 ESM 还是 CommonJS?

以 CommonJS 形式发布,可以直接 require();在 ES Module 项目中也可以用 import 引入(Node.js 会把 module.exports 作为默认导出)。

@cisstech/nestjs-pg-pubsub 可以商用吗?

@cisstech/nestjs-pg-pubsub 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@cisstech/nestjs-pg-pubsub 的下载量有多少?

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

@cisstech/nestjs-pg-pubsub 还在维护吗?

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