@wavezync/nestjs-pgboss 1.0.0-alpha
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.editorconfig +12 -0
- package/.eslintrc.js +33 -0
- package/.github/workflows/build.yaml +43 -0
- package/.github/workflows/release.yaml +40 -0
- package/LICENSE +21 -0
- package/README.MD +106 -0
- package/dist/decorators/job.decorator.d.ts +7 -0
- package/dist/decorators/job.decorator.js +24 -0
- package/dist/decorators/job.decorator.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +21 -0
- package/dist/index.js.map +1 -0
- package/dist/interfaces/pgboss-module-options.interface.d.ts +12 -0
- package/dist/interfaces/pgboss-module-options.interface.js +3 -0
- package/dist/interfaces/pgboss-module-options.interface.js.map +1 -0
- package/dist/pgboss.module.d.ts +7 -0
- package/dist/pgboss.module.js +73 -0
- package/dist/pgboss.module.js.map +1 -0
- package/dist/pgboss.service.d.ts +8 -0
- package/dist/pgboss.service.js +43 -0
- package/dist/pgboss.service.js.map +1 -0
- package/dist/utils/consts.d.ts +2 -0
- package/dist/utils/consts.js +6 -0
- package/dist/utils/consts.js.map +1 -0
- package/lib/decorators/job.decorator.ts +29 -0
- package/lib/index.ts +4 -0
- package/lib/interfaces/pgboss-module-options.interface.ts +18 -0
- package/lib/pgboss.module.ts +84 -0
- package/lib/pgboss.service.ts +40 -0
- package/lib/utils/consts.ts +2 -0
- package/nest-cli.json +8 -0
- package/package.json +70 -0
- package/test/jest-e2e.json +9 -0
- package/test/pgboss.service.spec.ts +81 -0
- package/tsconfig.build.json +16 -0
- package/tsconfig.json +36 -0
package/.editorconfig
ADDED
package/.eslintrc.js
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/** @type {import('eslint').ESLint.ConfigData} */
|
|
2
|
+
module.exports = {
|
|
3
|
+
parser: '@typescript-eslint/parser',
|
|
4
|
+
parserOptions: {
|
|
5
|
+
project: 'tsconfig.json',
|
|
6
|
+
sourceType: 'module',
|
|
7
|
+
},
|
|
8
|
+
plugins: ['@typescript-eslint/eslint-plugin'],
|
|
9
|
+
extends: [
|
|
10
|
+
'plugin:@typescript-eslint/recommended',
|
|
11
|
+
'plugin:prettier/recommended',
|
|
12
|
+
],
|
|
13
|
+
root: true,
|
|
14
|
+
env: {
|
|
15
|
+
node: true,
|
|
16
|
+
jest: true,
|
|
17
|
+
},
|
|
18
|
+
ignorePatterns: ['.eslintrc.js', 'tools/**'],
|
|
19
|
+
rules: {
|
|
20
|
+
'@typescript-eslint/interface-name-prefix': 'off',
|
|
21
|
+
'@typescript-eslint/explicit-function-return-type': 'off',
|
|
22
|
+
'@typescript-eslint/explicit-module-boundary-types': 'off',
|
|
23
|
+
'@typescript-eslint/no-explicit-any': 'off',
|
|
24
|
+
"@typescript-eslint/no-unused-vars": [
|
|
25
|
+
"error",
|
|
26
|
+
{
|
|
27
|
+
"args": "all",
|
|
28
|
+
"argsIgnorePattern": "^_",
|
|
29
|
+
"varsIgnorePattern": "^_",
|
|
30
|
+
}
|
|
31
|
+
],
|
|
32
|
+
},
|
|
33
|
+
};
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
name: Build
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags-ignore:
|
|
6
|
+
- "**"
|
|
7
|
+
branches:
|
|
8
|
+
- "**"
|
|
9
|
+
pull_request:
|
|
10
|
+
|
|
11
|
+
concurrency:
|
|
12
|
+
group: ${{ github.workflow }}-${{ github.ref }}
|
|
13
|
+
cancel-in-progress: true
|
|
14
|
+
|
|
15
|
+
jobs:
|
|
16
|
+
build:
|
|
17
|
+
runs-on: ubuntu-latest
|
|
18
|
+
|
|
19
|
+
steps:
|
|
20
|
+
- name: Check out Git repository
|
|
21
|
+
uses: actions/checkout@v4
|
|
22
|
+
|
|
23
|
+
- name: Setup Node
|
|
24
|
+
uses: actions/setup-node@v4
|
|
25
|
+
with:
|
|
26
|
+
node-version: "20"
|
|
27
|
+
|
|
28
|
+
- uses: actions/cache@v4
|
|
29
|
+
name: Setup npm cache
|
|
30
|
+
with:
|
|
31
|
+
path: ~/.npm
|
|
32
|
+
key: ${{ runner.os }}-npm-${{ hashFiles('package-lock.json') }}
|
|
33
|
+
restore-keys: |
|
|
34
|
+
${{ runner.os }}-npm-
|
|
35
|
+
|
|
36
|
+
- name: Install dependencies
|
|
37
|
+
run: npm ci
|
|
38
|
+
|
|
39
|
+
- name: Lint
|
|
40
|
+
run: npm run lint
|
|
41
|
+
|
|
42
|
+
- name: Build
|
|
43
|
+
run: npm run build
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
name: Publish to NPM
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
release:
|
|
5
|
+
types: [published]
|
|
6
|
+
|
|
7
|
+
jobs:
|
|
8
|
+
publish-npm:
|
|
9
|
+
runs-on: ubuntu-latest
|
|
10
|
+
steps:
|
|
11
|
+
- name: Check out Git repository
|
|
12
|
+
uses: actions/checkout@v4
|
|
13
|
+
|
|
14
|
+
- name: Setup Node
|
|
15
|
+
uses: actions/setup-node@v4
|
|
16
|
+
with:
|
|
17
|
+
node-version: "20"
|
|
18
|
+
registry-url: "https://registry.npmjs.org/"
|
|
19
|
+
|
|
20
|
+
- uses: actions/cache@v4
|
|
21
|
+
name: Setup npm cache
|
|
22
|
+
with:
|
|
23
|
+
path: ~/.npm
|
|
24
|
+
key: ${{ runner.os }}-npm-${{ hashFiles('package-lock.json') }}
|
|
25
|
+
restore-keys: |
|
|
26
|
+
${{ runner.os }}-npm-
|
|
27
|
+
|
|
28
|
+
- name: Install dependencies
|
|
29
|
+
run: npm ci
|
|
30
|
+
|
|
31
|
+
- name: Lint
|
|
32
|
+
run: npm run lint
|
|
33
|
+
|
|
34
|
+
- name: Build
|
|
35
|
+
run: npm run build
|
|
36
|
+
|
|
37
|
+
- name: Publish to NPM
|
|
38
|
+
run: npm publish --access public
|
|
39
|
+
env:
|
|
40
|
+
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Wavezync
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.MD
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
# `@wavezync/nestjs-pgboss`
|
|
2
|
+
|
|
3
|
+
<p align="center">
|
|
4
|
+
Use <a href="https://github.com/timgit/pg-boss" target="_blank">pg-boss</a> in your Nest.js service!
|
|
5
|
+
<p align="center">
|
|
6
|
+
|
|
7
|
+
<p align="center">
|
|
8
|
+
<a href="https://github.com/wavezync/nestjs-pgboss/actions/workflows/build.yaml">
|
|
9
|
+
<img src="https://img.shields.io/github/actions/workflow/status/wavezync/nestjs-pgboss/build.yaml?branch=main" alt="Build Status">
|
|
10
|
+
</a>
|
|
11
|
+
<a href="https://github.com/wavezync/nestjs-pgboss/blob/main/LICENSE">
|
|
12
|
+
<img src="https://img.shields.io/badge/License-MIT-green" alt="License">
|
|
13
|
+
</a>
|
|
14
|
+
</p>
|
|
15
|
+
|
|
16
|
+
## Installation
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npm install @wavezync/nestjs-pgboss
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Usage
|
|
23
|
+
|
|
24
|
+
### Setup
|
|
25
|
+
|
|
26
|
+
To begin using `@wavezync/nestjs-pgboss`, initialize the root module:
|
|
27
|
+
|
|
28
|
+
```ts
|
|
29
|
+
import { PGBossModule } from "@wavezync/nestjs-pgboss";
|
|
30
|
+
|
|
31
|
+
// app.module.ts
|
|
32
|
+
@Module({
|
|
33
|
+
imports: [
|
|
34
|
+
PgBossModule.forRootAsync({
|
|
35
|
+
imports: [ConfigModule],
|
|
36
|
+
useFactory: async (configService: ConfigService) => ({
|
|
37
|
+
connectionString: configService.get<string>('DATABASE_URL'),
|
|
38
|
+
}),
|
|
39
|
+
inject: [ConfigService],
|
|
40
|
+
}),
|
|
41
|
+
],
|
|
42
|
+
})
|
|
43
|
+
export class AppModule {}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Schedule a job using `PgBossService`:
|
|
47
|
+
|
|
48
|
+
```ts
|
|
49
|
+
import { Injectable } from '@nestjs/common';
|
|
50
|
+
import { PgBossService } from '@wavezync/nestjs-pgboss';
|
|
51
|
+
|
|
52
|
+
@Injectable()
|
|
53
|
+
export class JobSchedulerService {
|
|
54
|
+
constructor(private readonly pgBossService: PgBossService) {}
|
|
55
|
+
|
|
56
|
+
async scheduleJob() {
|
|
57
|
+
await this.pgBossService.scheduleJob('my-job', { key: 'value' });
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
```
|
|
62
|
+
Handle jobs using the `@Job` decorator:
|
|
63
|
+
|
|
64
|
+
```ts
|
|
65
|
+
import { Injectable, Logger } from '@nestjs/common';
|
|
66
|
+
import { Job } from '@wavezync/nestjs-pgboss';
|
|
67
|
+
|
|
68
|
+
@Injectable()
|
|
69
|
+
export class MyJobHandler {
|
|
70
|
+
private readonly logger = new Logger(MyJobHandler.name);
|
|
71
|
+
|
|
72
|
+
@Job('my-job')
|
|
73
|
+
async handleMyJob(job: { data: any }) {
|
|
74
|
+
this.logger.log('Handling job with data:', job.data);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
```
|
|
79
|
+
Handle cron jobs using the `@CronJob` decorator:
|
|
80
|
+
```ts
|
|
81
|
+
import { Injectable, Logger } from '@nestjs/common';
|
|
82
|
+
import { PgBossService, Cron } from '@wavezync/nestjs-pgboss';
|
|
83
|
+
|
|
84
|
+
@Injectable()
|
|
85
|
+
export class MyCronJobService {
|
|
86
|
+
private readonly logger = new Logger(MyCronJobService.name);
|
|
87
|
+
|
|
88
|
+
@CronJob('my-cron-job', '0 * * * *', { priority: 1 })
|
|
89
|
+
async handleCron() {
|
|
90
|
+
this.logger.log('Executing cron job: my-cron-job');
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## Test
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
# unit tests
|
|
100
|
+
$ npm run test
|
|
101
|
+
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## License
|
|
105
|
+
|
|
106
|
+
`@wavezync/nestjs-pgboss` is [MIT licensed](LICENSE).
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { JobOptions } from "pg-boss";
|
|
2
|
+
export declare const JOB_NAME = "JOB_NAME";
|
|
3
|
+
export declare const JOB_OPTIONS = "JOB_OPTIONS";
|
|
4
|
+
export declare const CRON_EXPRESSION = "CRON_EXPRESSION";
|
|
5
|
+
export declare const CRON_OPTIONS = "CRON_OPTIONS";
|
|
6
|
+
export declare function Job<_TData extends object = any>(name: string, options?: JobOptions): (target: any, key: string, descriptor: PropertyDescriptor) => void;
|
|
7
|
+
export declare function Cron<_TData extends object = any>(name: string, cron: string, options?: JobOptions): (target: any, key: string, descriptor: PropertyDescriptor) => void;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.CRON_OPTIONS = exports.CRON_EXPRESSION = exports.JOB_OPTIONS = exports.JOB_NAME = void 0;
|
|
4
|
+
exports.Job = Job;
|
|
5
|
+
exports.Cron = Cron;
|
|
6
|
+
const common_1 = require("@nestjs/common");
|
|
7
|
+
exports.JOB_NAME = "JOB_NAME";
|
|
8
|
+
exports.JOB_OPTIONS = "JOB_OPTIONS";
|
|
9
|
+
exports.CRON_EXPRESSION = "CRON_EXPRESSION";
|
|
10
|
+
exports.CRON_OPTIONS = "CRON_OPTIONS";
|
|
11
|
+
function Job(name, options = {}) {
|
|
12
|
+
return (target, key, descriptor) => {
|
|
13
|
+
(0, common_1.SetMetadata)(exports.JOB_NAME, name)(target, key, descriptor);
|
|
14
|
+
(0, common_1.SetMetadata)(exports.JOB_OPTIONS, options)(target, key, descriptor);
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
function Cron(name, cron, options = {}) {
|
|
18
|
+
return (target, key, descriptor) => {
|
|
19
|
+
(0, common_1.SetMetadata)(exports.JOB_NAME, name)(target, key, descriptor);
|
|
20
|
+
(0, common_1.SetMetadata)(exports.CRON_EXPRESSION, cron)(target, key, descriptor);
|
|
21
|
+
(0, common_1.SetMetadata)(exports.CRON_OPTIONS, options)(target, key, descriptor);
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=job.decorator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"job.decorator.js","sourceRoot":"","sources":["../../lib/decorators/job.decorator.ts"],"names":[],"mappings":";;;AAQA,kBAQC;AAED,oBAUC;AA5BD,2CAA6C;AAGhC,QAAA,QAAQ,GAAG,UAAU,CAAC;AACtB,QAAA,WAAW,GAAG,aAAa,CAAC;AAC5B,QAAA,eAAe,GAAG,iBAAiB,CAAC;AACpC,QAAA,YAAY,GAAG,cAAc,CAAC;AAE3C,SAAgB,GAAG,CACjB,IAAY,EACZ,UAAsB,EAAE;IAExB,OAAO,CAAC,MAAW,EAAE,GAAW,EAAE,UAA8B,EAAE,EAAE;QAClE,IAAA,oBAAW,EAAC,gBAAQ,EAAE,IAAI,CAAC,CAAC,MAAM,EAAE,GAAG,EAAE,UAAU,CAAC,CAAC;QACrD,IAAA,oBAAW,EAAC,mBAAW,EAAE,OAAO,CAAC,CAAC,MAAM,EAAE,GAAG,EAAE,UAAU,CAAC,CAAC;IAC7D,CAAC,CAAC;AACJ,CAAC;AAED,SAAgB,IAAI,CAClB,IAAY,EACZ,IAAY,EACZ,UAAsB,EAAE;IAExB,OAAO,CAAC,MAAW,EAAE,GAAW,EAAE,UAA8B,EAAE,EAAE;QAClE,IAAA,oBAAW,EAAC,gBAAQ,EAAE,IAAI,CAAC,CAAC,MAAM,EAAE,GAAG,EAAE,UAAU,CAAC,CAAC;QACrD,IAAA,oBAAW,EAAC,uBAAe,EAAE,IAAI,CAAC,CAAC,MAAM,EAAE,GAAG,EAAE,UAAU,CAAC,CAAC;QAC5D,IAAA,oBAAW,EAAC,oBAAY,EAAE,OAAO,CAAC,CAAC,MAAM,EAAE,GAAG,EAAE,UAAU,CAAC,CAAC;IAC9D,CAAC,CAAC;AACJ,CAAC"}
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./pgboss.module"), exports);
|
|
18
|
+
__exportStar(require("./pgboss.service"), exports);
|
|
19
|
+
__exportStar(require("./decorators/job.decorator"), exports);
|
|
20
|
+
__exportStar(require("./interfaces/pgboss-module-options.interface"), exports);
|
|
21
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../lib/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,kDAAgC;AAChC,mDAAiC;AACjC,6DAA2C;AAC3C,+EAA6D"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { ModuleMetadata, Type } from "@nestjs/common";
|
|
2
|
+
import { ConstructorOptions } from "pg-boss";
|
|
3
|
+
export type PgBossModuleOptions = ConstructorOptions;
|
|
4
|
+
export interface PgBossOptionsFactory {
|
|
5
|
+
createPgBossOptions(): Promise<PgBossModuleOptions> | PgBossModuleOptions;
|
|
6
|
+
}
|
|
7
|
+
export interface PgBossModuleAsyncOptions extends Pick<ModuleMetadata, "imports"> {
|
|
8
|
+
useExisting?: Type<PgBossOptionsFactory>;
|
|
9
|
+
useClass?: Type<PgBossOptionsFactory>;
|
|
10
|
+
useFactory?: (...args: any[]) => Promise<PgBossModuleOptions> | PgBossModuleOptions;
|
|
11
|
+
inject?: any[];
|
|
12
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pgboss-module-options.interface.js","sourceRoot":"","sources":["../../lib/interfaces/pgboss-module-options.interface.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { DynamicModule } from "@nestjs/common";
|
|
2
|
+
import { PgBossModuleAsyncOptions } from "./interfaces/pgboss-module-options.interface";
|
|
3
|
+
export declare class PgBossModule {
|
|
4
|
+
static forRootAsync(options: PgBossModuleAsyncOptions): DynamicModule;
|
|
5
|
+
private static createAsyncProviders;
|
|
6
|
+
private static createAsyncOptionsProvider;
|
|
7
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
9
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
10
|
+
};
|
|
11
|
+
var PgBossModule_1;
|
|
12
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
+
exports.PgBossModule = void 0;
|
|
14
|
+
const common_1 = require("@nestjs/common");
|
|
15
|
+
const pg_boss_1 = __importDefault(require("pg-boss"));
|
|
16
|
+
const pgboss_service_1 = require("./pgboss.service");
|
|
17
|
+
const consts_1 = require("./utils/consts");
|
|
18
|
+
let PgBossModule = PgBossModule_1 = class PgBossModule {
|
|
19
|
+
static forRootAsync(options) {
|
|
20
|
+
const logger = new common_1.Logger(PgBossModule_1.name);
|
|
21
|
+
const pgBossProvider = {
|
|
22
|
+
provide: consts_1.PGBOSS_TOKEN,
|
|
23
|
+
useFactory: async (pgBossOptions) => {
|
|
24
|
+
const boss = new pg_boss_1.default(pgBossOptions.connectionString);
|
|
25
|
+
await boss.start();
|
|
26
|
+
logger.log("PgBoss started successfully");
|
|
27
|
+
return boss;
|
|
28
|
+
},
|
|
29
|
+
inject: [consts_1.PGBOSS_OPTIONS],
|
|
30
|
+
};
|
|
31
|
+
const asyncProviders = this.createAsyncProviders(options);
|
|
32
|
+
return {
|
|
33
|
+
module: PgBossModule_1,
|
|
34
|
+
imports: options.imports || [],
|
|
35
|
+
providers: [...asyncProviders, pgBossProvider, pgboss_service_1.PgBossService],
|
|
36
|
+
exports: [pgboss_service_1.PgBossService],
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
static createAsyncProviders(options) {
|
|
40
|
+
if (options.useExisting || options.useFactory) {
|
|
41
|
+
return [this.createAsyncOptionsProvider(options)];
|
|
42
|
+
}
|
|
43
|
+
const useClass = options.useClass;
|
|
44
|
+
return [
|
|
45
|
+
this.createAsyncOptionsProvider(options),
|
|
46
|
+
{
|
|
47
|
+
provide: useClass,
|
|
48
|
+
useClass,
|
|
49
|
+
},
|
|
50
|
+
];
|
|
51
|
+
}
|
|
52
|
+
static createAsyncOptionsProvider(options) {
|
|
53
|
+
if (options.useFactory) {
|
|
54
|
+
return {
|
|
55
|
+
provide: consts_1.PGBOSS_OPTIONS,
|
|
56
|
+
useFactory: options.useFactory,
|
|
57
|
+
inject: options.inject || [],
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
const inject = [(options.useClass || options.useExisting)];
|
|
61
|
+
return {
|
|
62
|
+
provide: consts_1.PGBOSS_OPTIONS,
|
|
63
|
+
useFactory: async (optionsFactory) => optionsFactory.createPgBossOptions(),
|
|
64
|
+
inject,
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
exports.PgBossModule = PgBossModule;
|
|
69
|
+
exports.PgBossModule = PgBossModule = PgBossModule_1 = __decorate([
|
|
70
|
+
(0, common_1.Global)(),
|
|
71
|
+
(0, common_1.Module)({})
|
|
72
|
+
], PgBossModule);
|
|
73
|
+
//# sourceMappingURL=pgboss.module.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pgboss.module.js","sourceRoot":"","sources":["../lib/pgboss.module.ts"],"names":[],"mappings":";;;;;;;;;;;;;AACA,2CAMwB;AACxB,sDAA6B;AAC7B,qDAAiD;AACjD,2CAA8D;AAQvD,IAAM,YAAY,oBAAlB,MAAM,YAAY;IACvB,MAAM,CAAC,YAAY,CAAC,OAAiC;QACnD,MAAM,MAAM,GAAG,IAAI,eAAM,CAAC,cAAY,CAAC,IAAI,CAAC,CAAC;QAE7C,MAAM,cAAc,GAAa;YAC/B,OAAO,EAAE,qBAAY;YACrB,UAAU,EAAE,KAAK,EAAE,aAAa,EAAE,EAAE;gBAClC,MAAM,IAAI,GAAG,IAAI,iBAAM,CAAC,aAAa,CAAC,gBAAgB,CAAC,CAAC;gBACxD,MAAM,IAAI,CAAC,KAAK,EAAE,CAAC;gBACnB,MAAM,CAAC,GAAG,CAAC,6BAA6B,CAAC,CAAC;gBAC1C,OAAO,IAAI,CAAC;YACd,CAAC;YACD,MAAM,EAAE,CAAC,uBAAc,CAAC;SACzB,CAAC;QAEF,MAAM,cAAc,GAAG,IAAI,CAAC,oBAAoB,CAAC,OAAO,CAAC,CAAC;QAE1D,OAAO;YACL,MAAM,EAAE,cAAY;YACpB,OAAO,EAAE,OAAO,CAAC,OAAO,IAAI,EAAE;YAC9B,SAAS,EAAE,CAAC,GAAG,cAAc,EAAE,cAAc,EAAE,8BAAa,CAAC;YAC7D,OAAO,EAAE,CAAC,8BAAa,CAAC;SACzB,CAAC;IACJ,CAAC;IAEO,MAAM,CAAC,oBAAoB,CACjC,OAAiC;QAEjC,IAAI,OAAO,CAAC,WAAW,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC;YAC9C,OAAO,CAAC,IAAI,CAAC,0BAA0B,CAAC,OAAO,CAAC,CAAC,CAAC;QACpD,CAAC;QAED,MAAM,QAAQ,GAAG,OAAO,CAAC,QAEA,CAAC;QAE1B,OAAO;YACL,IAAI,CAAC,0BAA0B,CAAC,OAAO,CAAC;YACxC;gBACE,OAAO,EAAE,QAAQ;gBACjB,QAAQ;aACT;SACF,CAAC;IACJ,CAAC;IAEO,MAAM,CAAC,0BAA0B,CACvC,OAAiC;QAEjC,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC;YACvB,OAAO;gBACL,OAAO,EAAE,uBAAc;gBACvB,UAAU,EAAE,OAAO,CAAC,UAAU;gBAC9B,MAAM,EAAE,OAAO,CAAC,MAAM,IAAI,EAAE;aAC7B,CAAC;QACJ,CAAC;QAED,MAAM,MAAM,GAAG,CAAC,CAAC,OAAO,CAAC,QAAQ,IAAI,OAAO,CAAC,WAAW,CAAQ,CAAC,CAAC;QAElE,OAAO;YACL,OAAO,EAAE,uBAAc;YACvB,UAAU,EAAE,KAAK,EAAE,cAAoC,EAAE,EAAE,CACzD,cAAc,CAAC,mBAAmB,EAAE;YACtC,MAAM;SACP,CAAC;IACJ,CAAC;CACF,CAAA;AAjEY,oCAAY;uBAAZ,YAAY;IAFxB,IAAA,eAAM,GAAE;IACR,IAAA,eAAM,EAAC,EAAE,CAAC;GACE,YAAY,CAiExB"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import PgBoss, { BatchWorkOptions, JobOptions, WorkHandler } from "pg-boss";
|
|
2
|
+
export declare class PgBossService {
|
|
3
|
+
private readonly boss;
|
|
4
|
+
constructor(boss: PgBoss);
|
|
5
|
+
registerJob<TData extends object>(name: string, handler: WorkHandler<TData>, options?: BatchWorkOptions): Promise<void>;
|
|
6
|
+
scheduleJob<TData extends object>(name: string, data: TData, options?: JobOptions): Promise<void>;
|
|
7
|
+
registerCronJob<TData extends object>(name: string, cron: string, handler: WorkHandler<TData>, data?: TData, options?: PgBoss.ScheduleOptions): Promise<void>;
|
|
8
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
|
+
};
|
|
11
|
+
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
12
|
+
return function (target, key) { decorator(target, key, paramIndex); }
|
|
13
|
+
};
|
|
14
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
15
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
16
|
+
};
|
|
17
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
|
+
exports.PgBossService = void 0;
|
|
19
|
+
const common_1 = require("@nestjs/common");
|
|
20
|
+
const pg_boss_1 = __importDefault(require("pg-boss"));
|
|
21
|
+
const consts_1 = require("./utils/consts");
|
|
22
|
+
let PgBossService = class PgBossService {
|
|
23
|
+
constructor(boss) {
|
|
24
|
+
this.boss = boss;
|
|
25
|
+
}
|
|
26
|
+
async registerJob(name, handler, options) {
|
|
27
|
+
await this.boss.work(name, options, handler);
|
|
28
|
+
}
|
|
29
|
+
async scheduleJob(name, data, options) {
|
|
30
|
+
await this.boss.send(name, data, options);
|
|
31
|
+
}
|
|
32
|
+
async registerCronJob(name, cron, handler, data, options) {
|
|
33
|
+
await this.boss.schedule(name, cron, data ? data : {}, options ? options : {});
|
|
34
|
+
await this.boss.work(name, handler);
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
exports.PgBossService = PgBossService;
|
|
38
|
+
exports.PgBossService = PgBossService = __decorate([
|
|
39
|
+
(0, common_1.Injectable)(),
|
|
40
|
+
__param(0, (0, common_1.Inject)(consts_1.PGBOSS_TOKEN)),
|
|
41
|
+
__metadata("design:paramtypes", [pg_boss_1.default])
|
|
42
|
+
], PgBossService);
|
|
43
|
+
//# sourceMappingURL=pgboss.service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pgboss.service.js","sourceRoot":"","sources":["../lib/pgboss.service.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;AAAA,2CAAoD;AACpD,sDAA4E;AAC5E,2CAA8C;AAGvC,IAAM,aAAa,GAAnB,MAAM,aAAa;IACxB,YAAmD,IAAY;QAAZ,SAAI,GAAJ,IAAI,CAAQ;IAAG,CAAC;IAEnE,KAAK,CAAC,WAAW,CACf,IAAY,EACZ,OAA2B,EAC3B,OAA0B;QAE1B,MAAM,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;IAC/C,CAAC;IAED,KAAK,CAAC,WAAW,CACf,IAAY,EACZ,IAAW,EACX,OAAoB;QAEpB,MAAM,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;IAC5C,CAAC;IAED,KAAK,CAAC,eAAe,CACnB,IAAY,EACZ,IAAY,EACZ,OAA2B,EAC3B,IAAY,EACZ,OAAgC;QAEhC,MAAM,IAAI,CAAC,IAAI,CAAC,QAAQ,CACtB,IAAI,EACJ,IAAI,EACJ,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAChB,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CACvB,CAAC;QACF,MAAM,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IACtC,CAAC;CACF,CAAA;AAlCY,sCAAa;wBAAb,aAAa;IADzB,IAAA,mBAAU,GAAE;IAEE,WAAA,IAAA,eAAM,EAAC,qBAAY,CAAC,CAAA;qCAAwB,iBAAM;GADpD,aAAa,CAkCzB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"consts.js","sourceRoot":"","sources":["../../lib/utils/consts.ts"],"names":[],"mappings":";;;AAAa,QAAA,cAAc,GAAG,gBAAgB,CAAC;AAClC,QAAA,YAAY,GAAG,cAAc,CAAC"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { SetMetadata } from "@nestjs/common";
|
|
2
|
+
import { JobOptions } from "pg-boss";
|
|
3
|
+
|
|
4
|
+
export const JOB_NAME = "JOB_NAME";
|
|
5
|
+
export const JOB_OPTIONS = "JOB_OPTIONS";
|
|
6
|
+
export const CRON_EXPRESSION = "CRON_EXPRESSION";
|
|
7
|
+
export const CRON_OPTIONS = "CRON_OPTIONS";
|
|
8
|
+
|
|
9
|
+
export function Job<_TData extends object = any>(
|
|
10
|
+
name: string,
|
|
11
|
+
options: JobOptions = {},
|
|
12
|
+
) {
|
|
13
|
+
return (target: any, key: string, descriptor: PropertyDescriptor) => {
|
|
14
|
+
SetMetadata(JOB_NAME, name)(target, key, descriptor);
|
|
15
|
+
SetMetadata(JOB_OPTIONS, options)(target, key, descriptor);
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function CronJob<_TData extends object = any>(
|
|
20
|
+
name: string,
|
|
21
|
+
cron: string,
|
|
22
|
+
options: JobOptions = {},
|
|
23
|
+
) {
|
|
24
|
+
return (target: any, key: string, descriptor: PropertyDescriptor) => {
|
|
25
|
+
SetMetadata(JOB_NAME, name)(target, key, descriptor);
|
|
26
|
+
SetMetadata(CRON_EXPRESSION, cron)(target, key, descriptor);
|
|
27
|
+
SetMetadata(CRON_OPTIONS, options)(target, key, descriptor);
|
|
28
|
+
};
|
|
29
|
+
}
|
package/lib/index.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { ModuleMetadata, Type } from "@nestjs/common";
|
|
2
|
+
import { ConstructorOptions } from "pg-boss";
|
|
3
|
+
|
|
4
|
+
export type PgBossModuleOptions = ConstructorOptions;
|
|
5
|
+
|
|
6
|
+
export interface PgBossOptionsFactory {
|
|
7
|
+
createPgBossOptions(): Promise<PgBossModuleOptions> | PgBossModuleOptions;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface PgBossModuleAsyncOptions
|
|
11
|
+
extends Pick<ModuleMetadata, "imports"> {
|
|
12
|
+
useExisting?: Type<PgBossOptionsFactory>;
|
|
13
|
+
useClass?: Type<PgBossOptionsFactory>;
|
|
14
|
+
useFactory?: (
|
|
15
|
+
...args: any[]
|
|
16
|
+
) => Promise<PgBossModuleOptions> | PgBossModuleOptions;
|
|
17
|
+
inject?: any[];
|
|
18
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
// src/pg-boss.module.ts
|
|
2
|
+
import {
|
|
3
|
+
Module,
|
|
4
|
+
DynamicModule,
|
|
5
|
+
Global,
|
|
6
|
+
Provider,
|
|
7
|
+
Logger,
|
|
8
|
+
} from "@nestjs/common";
|
|
9
|
+
import PgBoss from "pg-boss";
|
|
10
|
+
import { PgBossService } from "./pgboss.service";
|
|
11
|
+
import { PGBOSS_OPTIONS, PGBOSS_TOKEN } from "./utils/consts";
|
|
12
|
+
import {
|
|
13
|
+
PgBossModuleAsyncOptions,
|
|
14
|
+
PgBossOptionsFactory,
|
|
15
|
+
} from "./interfaces/pgboss-module-options.interface";
|
|
16
|
+
|
|
17
|
+
@Global()
|
|
18
|
+
@Module({})
|
|
19
|
+
export class PgBossModule {
|
|
20
|
+
static forRootAsync(options: PgBossModuleAsyncOptions): DynamicModule {
|
|
21
|
+
const logger = new Logger(PgBossModule.name);
|
|
22
|
+
|
|
23
|
+
const pgBossProvider: Provider = {
|
|
24
|
+
provide: PGBOSS_TOKEN,
|
|
25
|
+
useFactory: async (pgBossOptions) => {
|
|
26
|
+
const boss = new PgBoss(pgBossOptions.connectionString);
|
|
27
|
+
await boss.start();
|
|
28
|
+
logger.log("PgBoss started successfully");
|
|
29
|
+
return boss;
|
|
30
|
+
},
|
|
31
|
+
inject: [PGBOSS_OPTIONS],
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
const asyncProviders = this.createAsyncProviders(options);
|
|
35
|
+
|
|
36
|
+
return {
|
|
37
|
+
module: PgBossModule,
|
|
38
|
+
imports: options.imports || [],
|
|
39
|
+
providers: [...asyncProviders, pgBossProvider, PgBossService],
|
|
40
|
+
exports: [PgBossService],
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
private static createAsyncProviders(
|
|
45
|
+
options: PgBossModuleAsyncOptions,
|
|
46
|
+
): Provider[] {
|
|
47
|
+
if (options.useExisting || options.useFactory) {
|
|
48
|
+
return [this.createAsyncOptionsProvider(options)];
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const useClass = options.useClass as new (
|
|
52
|
+
...args: any[]
|
|
53
|
+
) => PgBossOptionsFactory;
|
|
54
|
+
|
|
55
|
+
return [
|
|
56
|
+
this.createAsyncOptionsProvider(options),
|
|
57
|
+
{
|
|
58
|
+
provide: useClass,
|
|
59
|
+
useClass,
|
|
60
|
+
},
|
|
61
|
+
];
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
private static createAsyncOptionsProvider(
|
|
65
|
+
options: PgBossModuleAsyncOptions,
|
|
66
|
+
): Provider {
|
|
67
|
+
if (options.useFactory) {
|
|
68
|
+
return {
|
|
69
|
+
provide: PGBOSS_OPTIONS,
|
|
70
|
+
useFactory: options.useFactory,
|
|
71
|
+
inject: options.inject || [],
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const inject = [(options.useClass || options.useExisting) as any];
|
|
76
|
+
|
|
77
|
+
return {
|
|
78
|
+
provide: PGBOSS_OPTIONS,
|
|
79
|
+
useFactory: async (optionsFactory: PgBossOptionsFactory) =>
|
|
80
|
+
optionsFactory.createPgBossOptions(),
|
|
81
|
+
inject,
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { Inject, Injectable } from "@nestjs/common";
|
|
2
|
+
import PgBoss, { BatchWorkOptions, JobOptions, WorkHandler } from "pg-boss";
|
|
3
|
+
import { PGBOSS_TOKEN } from "./utils/consts";
|
|
4
|
+
|
|
5
|
+
@Injectable()
|
|
6
|
+
export class PgBossService {
|
|
7
|
+
constructor(@Inject(PGBOSS_TOKEN) private readonly boss: PgBoss) {}
|
|
8
|
+
|
|
9
|
+
async registerJob<TData extends object>(
|
|
10
|
+
name: string,
|
|
11
|
+
handler: WorkHandler<TData>,
|
|
12
|
+
options?: BatchWorkOptions,
|
|
13
|
+
) {
|
|
14
|
+
await this.boss.work(name, options, handler);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
async scheduleJob<TData extends object>(
|
|
18
|
+
name: string,
|
|
19
|
+
data: TData,
|
|
20
|
+
options?: JobOptions,
|
|
21
|
+
) {
|
|
22
|
+
await this.boss.send(name, data, options);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
async registerCronJob<TData extends object>(
|
|
26
|
+
name: string,
|
|
27
|
+
cron: string,
|
|
28
|
+
handler: WorkHandler<TData>,
|
|
29
|
+
data?: TData,
|
|
30
|
+
options?: PgBoss.ScheduleOptions,
|
|
31
|
+
) {
|
|
32
|
+
await this.boss.schedule(
|
|
33
|
+
name,
|
|
34
|
+
cron,
|
|
35
|
+
data ? data : {},
|
|
36
|
+
options ? options : {},
|
|
37
|
+
);
|
|
38
|
+
await this.boss.work(name, handler);
|
|
39
|
+
}
|
|
40
|
+
}
|
package/nest-cli.json
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@wavezync/nestjs-pgboss",
|
|
3
|
+
"version": "1.0.0-alpha",
|
|
4
|
+
"description": "A NestJS module that integrates pg-boss for job scheduling and handling.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"author": "samaratungajs@wavezync.com",
|
|
7
|
+
"main": "dist/index.js",
|
|
8
|
+
"types": "dist/index.d.ts",
|
|
9
|
+
"scripts": {
|
|
10
|
+
"build": "nest build",
|
|
11
|
+
"format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
|
|
12
|
+
"start": "nest start",
|
|
13
|
+
"start:dev": "nest start --watch",
|
|
14
|
+
"start:debug": "nest start --debug --watch",
|
|
15
|
+
"start:prod": "node dist/main",
|
|
16
|
+
"lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix",
|
|
17
|
+
"test": "jest",
|
|
18
|
+
"test:watch": "jest --watch",
|
|
19
|
+
"test:cov": "jest --coverage",
|
|
20
|
+
"test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand",
|
|
21
|
+
"test:e2e": "jest --config ./test/jest-e2e.json"
|
|
22
|
+
},
|
|
23
|
+
"peerDependencies": {
|
|
24
|
+
"@nestjs/common": "^9 || ^10",
|
|
25
|
+
"@nestjs/core": "^9 || ^10",
|
|
26
|
+
"pg-boss": "^9",
|
|
27
|
+
"reflect-metadata": "^0.1.13 || ^0.2.0",
|
|
28
|
+
"rxjs": "^7.2.0"
|
|
29
|
+
},
|
|
30
|
+
"devDependencies": {
|
|
31
|
+
"@nestjs/cli": "^10.0.0",
|
|
32
|
+
"@nestjs/schematics": "^10.0.0",
|
|
33
|
+
"@nestjs/testing": "^10.0.0",
|
|
34
|
+
"@types/express": "^4.17.17",
|
|
35
|
+
"@types/jest": "^29.5.2",
|
|
36
|
+
"@types/node": "^20.3.1",
|
|
37
|
+
"@types/supertest": "^6.0.0",
|
|
38
|
+
"@typescript-eslint/eslint-plugin": "^7.0.0",
|
|
39
|
+
"@typescript-eslint/parser": "^7.0.0",
|
|
40
|
+
"eslint": "^8.42.0",
|
|
41
|
+
"eslint-config-prettier": "^9.0.0",
|
|
42
|
+
"eslint-plugin-prettier": "^5.0.0",
|
|
43
|
+
"jest": "^29.5.0",
|
|
44
|
+
"prettier": "^3.0.0",
|
|
45
|
+
"source-map-support": "^0.5.21",
|
|
46
|
+
"supertest": "^7.0.0",
|
|
47
|
+
"ts-jest": "^29.1.0",
|
|
48
|
+
"ts-loader": "^9.4.3",
|
|
49
|
+
"ts-node": "^10.9.1",
|
|
50
|
+
"tsconfig-paths": "^4.2.0",
|
|
51
|
+
"typescript": "^5.1.3"
|
|
52
|
+
},
|
|
53
|
+
"jest": {
|
|
54
|
+
"roots": [
|
|
55
|
+
"<rootDir>/test"
|
|
56
|
+
],
|
|
57
|
+
"transform": {
|
|
58
|
+
"^.+\\.(t|j)s$": "ts-jest"
|
|
59
|
+
},
|
|
60
|
+
"testEnvironment": "node",
|
|
61
|
+
"moduleFileExtensions": [
|
|
62
|
+
"ts",
|
|
63
|
+
"js"
|
|
64
|
+
]
|
|
65
|
+
},
|
|
66
|
+
"repository": {
|
|
67
|
+
"type": "git",
|
|
68
|
+
"url": "https://github.com/wavezync/nestjs-pgboss"
|
|
69
|
+
}
|
|
70
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { Test, TestingModule } from "@nestjs/testing";
|
|
2
|
+
import PgBoss from "pg-boss";
|
|
3
|
+
import { PgBossService } from "../lib/pgboss.service";
|
|
4
|
+
import { PGBOSS_TOKEN } from "../lib/utils/consts";
|
|
5
|
+
|
|
6
|
+
describe("PgBossService", () => {
|
|
7
|
+
let service: PgBossService;
|
|
8
|
+
let mockPgBoss: jest.Mocked<PgBoss>;
|
|
9
|
+
|
|
10
|
+
beforeEach(async () => {
|
|
11
|
+
mockPgBoss = {
|
|
12
|
+
start: jest.fn(),
|
|
13
|
+
work: jest.fn(),
|
|
14
|
+
send: jest.fn(),
|
|
15
|
+
schedule: jest.fn(),
|
|
16
|
+
} as any;
|
|
17
|
+
|
|
18
|
+
const module: TestingModule = await Test.createTestingModule({
|
|
19
|
+
providers: [
|
|
20
|
+
PgBossService,
|
|
21
|
+
{ provide: PGBOSS_TOKEN, useValue: mockPgBoss },
|
|
22
|
+
],
|
|
23
|
+
}).compile();
|
|
24
|
+
|
|
25
|
+
service = module.get<PgBossService>(PgBossService);
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it("should be defined", () => {
|
|
29
|
+
expect(service).toBeDefined();
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
describe("registerJob", () => {
|
|
33
|
+
it("should call PgBoss work with correct parameters", async () => {
|
|
34
|
+
const handler = jest.fn();
|
|
35
|
+
const options = { batchSize: 5 };
|
|
36
|
+
|
|
37
|
+
await service.registerJob("test-job", handler, options);
|
|
38
|
+
|
|
39
|
+
expect(mockPgBoss.work).toHaveBeenCalledWith(
|
|
40
|
+
"test-job",
|
|
41
|
+
{ batchSize: 5 },
|
|
42
|
+
handler,
|
|
43
|
+
);
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
describe("scheduleJob", () => {
|
|
48
|
+
it("should call PgBoss send with correct parameters", async () => {
|
|
49
|
+
const data = { test: "data" };
|
|
50
|
+
|
|
51
|
+
await service.scheduleJob("test-job", data, {});
|
|
52
|
+
|
|
53
|
+
expect(mockPgBoss.send).toHaveBeenCalledWith("test-job", data, {});
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
describe("registerCronJob", () => {
|
|
58
|
+
it("should call PgBoss schedule and work with correct parameters", async () => {
|
|
59
|
+
const handler = jest.fn();
|
|
60
|
+
const cron = "* * * * *";
|
|
61
|
+
const data = { test: "data" };
|
|
62
|
+
const options = { tz: "UTC" };
|
|
63
|
+
|
|
64
|
+
await service.registerCronJob(
|
|
65
|
+
"test-cron-job",
|
|
66
|
+
cron,
|
|
67
|
+
handler,
|
|
68
|
+
data,
|
|
69
|
+
options,
|
|
70
|
+
);
|
|
71
|
+
|
|
72
|
+
expect(mockPgBoss.schedule).toHaveBeenCalledWith(
|
|
73
|
+
"test-cron-job",
|
|
74
|
+
cron,
|
|
75
|
+
data,
|
|
76
|
+
{ tz: "UTC" },
|
|
77
|
+
);
|
|
78
|
+
expect(mockPgBoss.work).toHaveBeenCalledWith("test-cron-job", handler);
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
});
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"module": "commonjs",
|
|
4
|
+
"declaration": true,
|
|
5
|
+
"removeComments": true,
|
|
6
|
+
"resolveJsonModule": true,
|
|
7
|
+
"emitDecoratorMetadata": true,
|
|
8
|
+
"experimentalDecorators": true,
|
|
9
|
+
"esModuleInterop": true,
|
|
10
|
+
"allowSyntheticDefaultImports": true,
|
|
11
|
+
"target": "es2017",
|
|
12
|
+
"sourceMap": true,
|
|
13
|
+
"outDir": "./dist",
|
|
14
|
+
"baseUrl": "lib",
|
|
15
|
+
"incremental": false,
|
|
16
|
+
"skipLibCheck": true,
|
|
17
|
+
"strictNullChecks": false,
|
|
18
|
+
"noImplicitAny": false,
|
|
19
|
+
"strictBindCallApply": false,
|
|
20
|
+
"forceConsistentCasingInFileNames": false,
|
|
21
|
+
"noFallthroughCasesInSwitch": false,
|
|
22
|
+
"types": [
|
|
23
|
+
"@types/node",
|
|
24
|
+
"jest"
|
|
25
|
+
],
|
|
26
|
+
"strict": true
|
|
27
|
+
},
|
|
28
|
+
"include": [
|
|
29
|
+
"lib/**/*.ts",
|
|
30
|
+
"test/**/*.ts"
|
|
31
|
+
],
|
|
32
|
+
"exclude": [
|
|
33
|
+
"node_modules",
|
|
34
|
+
"dist"
|
|
35
|
+
]
|
|
36
|
+
}
|