{"id":13818179,"url":"https://github.com/pvarentsov/nestjs-pg-notify","last_synced_at":"2025-05-07T09:47:11.691Z","repository":{"id":44386190,"uuid":"350073448","full_name":"pvarentsov/nestjs-pg-notify","owner":"pvarentsov","description":"NestJS custom transport strategy for PostgreSQL Pub/Sub.","archived":false,"fork":false,"pushed_at":"2023-10-12T21:30:45.000Z","size":1345,"stargazers_count":82,"open_issues_count":1,"forks_count":3,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-05-01T06:19:15.470Z","etag":null,"topics":["microservice","nestjs","nestjs-custom-transporter","nestjs-pg-notify","pg-listen","pg-notify","pg-pubsub"],"latest_commit_sha":null,"homepage":"https://pvarentsov.github.io/nestjs-pg-notify","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/pvarentsov.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2021-03-21T17:42:52.000Z","updated_at":"2025-04-27T22:26:11.000Z","dependencies_parsed_at":"2024-01-15T20:49:50.794Z","dependency_job_id":"12b62921-1fcf-450f-927e-08eff0260dd5","html_url":"https://github.com/pvarentsov/nestjs-pg-notify","commit_stats":null,"previous_names":[],"tags_count":23,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pvarentsov%2Fnestjs-pg-notify","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pvarentsov%2Fnestjs-pg-notify/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pvarentsov%2Fnestjs-pg-notify/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pvarentsov%2Fnestjs-pg-notify/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/pvarentsov","download_url":"https://codeload.github.com/pvarentsov/nestjs-pg-notify/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252854337,"owners_count":21814669,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["microservice","nestjs","nestjs-custom-transporter","nestjs-pg-notify","pg-listen","pg-notify","pg-pubsub"],"created_at":"2024-08-04T07:00:35.109Z","updated_at":"2025-05-07T09:47:11.653Z","avatar_url":"https://github.com/pvarentsov.png","language":"TypeScript","funding_links":[],"categories":["Components \u0026 Libraries","TypeScript"],"sub_categories":[],"readme":"# NestJS PG Notify\n\n\u003e NestJS custom transport strategy for PostgreSQL Pub/Sub.\n\n[![License: MIT](https://img.shields.io/github/license/pvarentsov/nestjs-pg-notify)](./LICENSE)\n[![NPM Version](https://img.shields.io/npm/v/nestjs-pg-notify.svg)](https://www.npmjs.com/package/nestjs-pg-notify)\n[![NPM Downloads](https://img.shields.io/npm/dt/nestjs-pg-notify.svg)](https://www.npmjs.com/package/nestjs-pg-notify)\n\u003c!-- [![CI Status](https://img.shields.io/github/actions/workflow/status/pvarentsov/nestjs-pg-notify/npm-release.yaml)](https://github.com/pvarentsov/nestjs-pg-notify/actions/workflows/npm-release.yaml)\n[![Quality Gate Status](https://img.shields.io/sonar/quality_gate/pvarentsov_nestjs-pg-notify?server=https%3A%2F%2Fsonarcloud.io)](https://sonarcloud.io/dashboard?id=pvarentsov_nestjs-pg-notify)\n[![Coverage](https://img.shields.io/sonar/coverage/pvarentsov_nestjs-pg-notify?server=https%3A%2F%2Fsonarcloud.io)](https://sonarcloud.io/dashboard?id=pvarentsov_nestjs-pg-notify) --\u003e\n\n## PostgreSQL async notifications\n\nPostgreSQL can be used as a Pub/Sub message broker.\nIts functionality is similar to the Redis Pub/Sub, but has its own features and limitations.\n\nThe [References](#References) section contains links that you may find useful to familiarize yourself with the PostgreSQL asynchronous notifications.\n\n## Custom transporter\n\n**NestJS PG Notify** implements Pub/Sub messaging paradigm using PostgreSQL as a [NestJS custom transporter](https://docs.nestjs.com/microservices/custom-transport). \nIt wraps the [pg-listen](https://github.com/andywer/pg-listen) library under the hood. \n\nIt can be used in [microservice](https://docs.nestjs.com/microservices/basics) and [hybrid](https://docs.nestjs.com/faq/hybrid-application) \nNestJS applications. The [example](./example) folder contains examples for both types of applications.\n\n## Installation\n\n```bash\n$ npm i nestjs-pg-notify pg\n```\n\n## Usage\n\n### Setup `PgNotifyServer` as custom strategy\n\n```typescript\nimport { PgNotifyServer } from 'nestjs-pg-notify';\n\nconst app = await NestFactory.createMicroservice\u003cMicroserviceOptions\u003e(AppModule, {\n  strategy: new PgNotifyServer({\n    /**\n     * Required parameter\n     * Corresponds to the \"pg\" library's connection config\n     */  \n    connection: {\n      host: 'localhost',\n      port: 5432,\n      database: 'pgnotify',\n      user: 'pgnotify',\n      password: 'pgnotify',\n    },\n    /**\n     * Optional parameter\n     * Contains retry-strategy config passing the data to the \"pg-listen\" library\n     */\n    strategy: {\n      retryInterval: 1_000,\n      retryTimeout: Infinity,\n    },\n    /**\n     * Optional parameter\n     * Overrides default logger\n     */\n    logger: new Logger(),\n  })\n});\n```\n\n### Bind message handlers\n\n**NestJS PG Notify** offers two decorators to register message handlers: \n* `@PgNotifyEventPattern()`\n* `@PgNotifyMessagePattern()`\n \nThese are an alternative to standard decorators: \n* `@EventPattern()`\n* `@MessagePattern()`\n\nMessage handler's binding can be used only within controller classes.\n\n```typescript\nimport { PgNotifyContext, PgNotifyEventPattern, PgNotifyMessagePattern } from 'nestjs-pg-notify';\n\n@Controller()\nexport class AppController {\n\n  @PgNotifyEventPattern({event: 'greeting'})\n  @UsePipes(new ValidationPipe())\n  onGreetingEvent(@Payload() payload: any, @Ctx() context: PgNotifyContext): void {\n    Logger.log(payload.message);\n  }\n\n  @PgNotifyMessagePattern('greeting')\n  @UsePipes(new ValidationPipe())\n  onGreetingRequest(@Payload() payload: any, @Ctx() context: PgNotifyContext): string {\n    Logger.log(payload.message);\n    return 'Hello!';\n  }\n\n}\n```\n\nThe standard decorator `@Ctx()` allows access to the context of the incoming request. In our case, the context object is an instance of `PgNotifyContext`. \n\n### Setup `PgNotifyClient` as client proxy\n\nThe client proxy can be registered as a custom provider. The configuration is the same as the configuration of the `PgNotifyServer`.\n\n```typescript\nimport { PgNotifyClient } from 'nestjs-pg-notify';\n\n@Module({\n  providers: [\n    {\n      provide: 'PG_NOTIFY_CLIENT',\n      useFactory: (): ClientProxy =\u003e new PgNotifyClient({\n        connection: {\n          host: 'localhost',\n          port: 5432,\n          database: 'pgnotify',\n          user: 'pgnotify',\n          password: 'pgnotify',\n        },\n        strategy: {\n          retryInterval: 1_000,\n          retryTimeout: Infinity,\n        }, \n      })\n    },\n  ],\n  exports: [\n    'PG_NOTIFY_CLIENT',\n  ]\n})\nexport class AppModule {}\n```\n\nThen we can inject the client proxy.\n\n```typescript\nimport { PgNotifyResponse } from 'nestjs-pg-notify';\n\nexport class AppService {\n  constructor(\n    @Inject('PG_NOTIFY_CLIENT')\n    private readonly client: ClientProxy,\n  ) {}\n   \n  sendRequest(): Observable\u003cPgNotifyResponse\u003e {\n    // Send request and expect response\n    return this.client.send('greeting', {message: 'Hello!'}).pipe(\n      timeout(2_000),\n      tap(response =\u003e Logger.debug(response)),\n    );\n  }\n  \n  emitEvent(): Observable\u003cvoid\u003e {\n    // Emit event\n    return this.client.emit({event: 'greeting'}, {message: 'Hello!'});\n  }\n}\n```\n\n### Exception filters\n\nThe client proxy generates request identifier when we send requests using `client.send()`.\nThe request identifier in the context of the incoming request means that we need to prepare an error response for the client. \n\nWe can use the `PgNotifyResponse.error()` factory in order to unify the structure of the response.\n\n```typescript\nimport { PgNotifyContext, PgNotifyResponse } from 'nestjs-pg-notify';\n\n@Catch()\nexport class ExceptionFilter implements ExceptionFilter {\n  catch(error: Error, host: ArgumentsHost): Observable\u003cPgNotifyResponse|void\u003e {\n    const {status, message} = parseError(error);\n    const context = host.switchToRpc().getContext\u003cPgNotifyContext\u003e();\n    const requestId = context.getRequestId();\n\n    Logger.error(message, error.stack, 'PgNotifyExceptionFilter');\n\n    if (requestId) {\n      return of(PgNotifyResponse.error(message, status));\n    }\n\n    return of(undefined);\n  }\n}\n```\n\nThen we can register the filter using the standard `@UseFilters()` decorator. It supports method-scope and controller-scope modes.\n\n```typescript\n@Controller()\n@UseFilters(ExceptionFilter)\nexport class AppController {\n  // ...\n}\n```\n\n### Interceptors\n\n```typescript\nimport { PgNotifyContext } from 'nestjs-pg-notify';\n\n@Injectable()\nexport class LoggingInterceptor implements NestInterceptor {\n  public intercept(context: ExecutionContext, next: CallHandler): Observable\u003cvoid\u003e {\n    const pgNotifyContext = context\n      .switchToRpc()\n      .getContext\u003cPgNotifyContext\u003e();\n\n    return next.handle().pipe(\n      tap(() =\u003e Logger.log(JSON.stringify(pgNotifyContext), LoggingInterceptor.name)),\n    );\n  }\n}\n```\n\nTo register interceptor we can use `@UseInterceptors()` decorator. It also supports method-scope and controller-scope modes.\n\n```typescript\n@Controller()\n@UseInterceptors(LoggingInterceptor)\nexport class AppController {\n  // ...\n}\n```\n\n## API\n\nAPI documentation is available [here](https://pvarentsov.github.io/nestjs-pg-notify).\n\n## References\n\n1. PostgreSQL Documentation:\n   * [Asynchronous Notification](https://www.postgresql.org/docs/9.6/libpq-notify.html)\n   * [NOTIFY](https://www.postgresql.org/docs/9.6/sql-notify.html)\n   * [LISTEN](https://www.postgresql.org/docs/9.6/sql-listen.html) \n2. PgBouncer Documentation:\n   * [Transaction pool mode does not support NOTIFY/LISTEN features](https://www.pgbouncer.org/features.html)\n3. NestJS Documentation:\n   * [Microservices](https://docs.nestjs.com/microservices/basics)\n   * [Hybrid applications](https://docs.nestjs.com/faq/hybrid-application)\n   * [Custom transporters](https://docs.nestjs.com/microservices/custom-transport)\n4. Dependencies:\n   * [pg-listen](https://github.com/andywer/pg-listen)\n   \n## License\n\nThis project is licensed under the [MIT License](https://github.com/pvarentsov/nestjs-pg-notify/blob/main/LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpvarentsov%2Fnestjs-pg-notify","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpvarentsov%2Fnestjs-pg-notify","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpvarentsov%2Fnestjs-pg-notify/lists"}