@wavezync/nestjs-pgboss 5.0.0 → 5.1.0
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/dist/handler-scanner.service.js +6 -2
- package/dist/handler-scanner.service.js.map +1 -1
- package/dist/interfaces/handler-metadata.interface.d.ts +4 -1
- package/lib/handler-scanner.service.ts +11 -7
- package/lib/interfaces/handler-metadata.interface.ts +5 -1
- package/package.json +1 -1
- package/test/handler-scanner.service.spec.ts +82 -0
|
@@ -31,6 +31,7 @@ let HandlerScannerService = class HandlerScannerService {
|
|
|
31
31
|
}
|
|
32
32
|
}
|
|
33
33
|
async scanProvider(provider) {
|
|
34
|
+
var _a;
|
|
34
35
|
const { instance } = provider;
|
|
35
36
|
if (!instance || typeof instance !== "object")
|
|
36
37
|
return;
|
|
@@ -49,8 +50,11 @@ let HandlerScannerService = class HandlerScannerService {
|
|
|
49
50
|
this.logger.log(`Registered cron job: ${jobName}`);
|
|
50
51
|
continue;
|
|
51
52
|
}
|
|
52
|
-
|
|
53
|
-
|
|
53
|
+
const teamSize = Math.max(1, (_a = jobOptions === null || jobOptions === void 0 ? void 0 : jobOptions.teamSize) !== null && _a !== void 0 ? _a : 1);
|
|
54
|
+
for (let i = 0; i < teamSize; i++) {
|
|
55
|
+
await this.pgBossService.registerJob(jobName, methodRef.bind(instance), jobOptions);
|
|
56
|
+
}
|
|
57
|
+
this.logger.log(`Registered job: ${jobName} (${teamSize} worker${teamSize > 1 ? 's' : ''})`);
|
|
54
58
|
}
|
|
55
59
|
catch (error) {
|
|
56
60
|
this.logger.error(error, `Error registering job ${jobName}`);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"handler-scanner.service.js","sourceRoot":"","sources":["../lib/handler-scanner.service.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,2CAAoD;AACpD,uCAA2D;AAC3D,qDAAiD;AACjD,8DAKoC;AAGpC,2CAAwC;
|
|
1
|
+
{"version":3,"file":"handler-scanner.service.js","sourceRoot":"","sources":["../lib/handler-scanner.service.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
import { WorkOptions, ScheduleOptions } from "pg-boss";
|
|
1
|
+
import { WorkOptions as PgBossWorkOptions, ScheduleOptions } from "pg-boss";
|
|
2
|
+
export interface WorkOptions extends PgBossWorkOptions {
|
|
3
|
+
teamSize?: number;
|
|
4
|
+
}
|
|
2
5
|
export interface HandlerMetadata {
|
|
3
6
|
jobName: string;
|
|
4
7
|
workOptions?: WorkOptions;
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
import { InstanceWrapper } from "@nestjs/core/injector/instance-wrapper";
|
|
11
11
|
import PgBoss from "pg-boss";
|
|
12
12
|
import { LOGGER } from "./utils/consts";
|
|
13
|
+
import { WorkOptions } from "./interfaces/handler-metadata.interface";
|
|
13
14
|
|
|
14
15
|
@Injectable()
|
|
15
16
|
export class HandlerScannerService {
|
|
@@ -45,7 +46,7 @@ export class HandlerScannerService {
|
|
|
45
46
|
const methodRef = instance[methodName];
|
|
46
47
|
|
|
47
48
|
const jobName = this.reflector.get<string>(JOB_NAME, methodRef);
|
|
48
|
-
const jobOptions = this.reflector.get<
|
|
49
|
+
const jobOptions = this.reflector.get<WorkOptions>(
|
|
49
50
|
JOB_OPTIONS,
|
|
50
51
|
methodRef,
|
|
51
52
|
);
|
|
@@ -72,12 +73,15 @@ export class HandlerScannerService {
|
|
|
72
73
|
continue;
|
|
73
74
|
}
|
|
74
75
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
76
|
+
const teamSize = Math.max(1, jobOptions?.teamSize ?? 1);
|
|
77
|
+
for (let i = 0; i < teamSize; i++) {
|
|
78
|
+
await this.pgBossService.registerJob(
|
|
79
|
+
jobName,
|
|
80
|
+
methodRef.bind(instance),
|
|
81
|
+
jobOptions,
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
this.logger.log(`Registered job: ${jobName} (${teamSize} worker${teamSize > 1 ? 's' : ''})`);
|
|
81
85
|
} catch (error) {
|
|
82
86
|
this.logger.error(error, `Error registering job ${jobName}`);
|
|
83
87
|
}
|
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
import { WorkOptions, ScheduleOptions } from "pg-boss";
|
|
1
|
+
import { WorkOptions as PgBossWorkOptions, ScheduleOptions } from "pg-boss";
|
|
2
|
+
|
|
3
|
+
export interface WorkOptions extends PgBossWorkOptions {
|
|
4
|
+
teamSize?: number;
|
|
5
|
+
}
|
|
2
6
|
|
|
3
7
|
export interface HandlerMetadata {
|
|
4
8
|
jobName: string;
|
package/package.json
CHANGED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
jest.mock("pg-boss", () => ({}));
|
|
2
|
+
|
|
3
|
+
import { Test, TestingModule } from "@nestjs/testing";
|
|
4
|
+
import { Reflector, ModulesContainer } from "@nestjs/core";
|
|
5
|
+
import { HandlerScannerService } from "../lib/handler-scanner.service";
|
|
6
|
+
import { PgBossService } from "../lib/pgboss.service";
|
|
7
|
+
import { JOB_NAME, JOB_OPTIONS } from "../lib/decorators/job.decorator";
|
|
8
|
+
|
|
9
|
+
describe("HandlerScannerService", () => {
|
|
10
|
+
let service: HandlerScannerService;
|
|
11
|
+
let mockPgBossService: any;
|
|
12
|
+
let mockReflector: any;
|
|
13
|
+
let mockModulesContainer: Map<string, any>;
|
|
14
|
+
|
|
15
|
+
class TestHandler {
|
|
16
|
+
handle() {}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
beforeEach(async () => {
|
|
20
|
+
mockPgBossService = {
|
|
21
|
+
registerJob: jest.fn().mockResolvedValue(undefined),
|
|
22
|
+
registerCronJob: jest.fn().mockResolvedValue(undefined),
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
mockReflector = { get: jest.fn() };
|
|
26
|
+
mockModulesContainer = new Map();
|
|
27
|
+
|
|
28
|
+
const module: TestingModule = await Test.createTestingModule({
|
|
29
|
+
providers: [
|
|
30
|
+
HandlerScannerService,
|
|
31
|
+
{ provide: PgBossService, useValue: mockPgBossService },
|
|
32
|
+
{ provide: Reflector, useValue: mockReflector },
|
|
33
|
+
{ provide: ModulesContainer, useValue: mockModulesContainer },
|
|
34
|
+
],
|
|
35
|
+
}).compile();
|
|
36
|
+
|
|
37
|
+
service = module.get<HandlerScannerService>(HandlerScannerService);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
afterEach(() => {
|
|
41
|
+
jest.clearAllMocks();
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
describe("teamSize", () => {
|
|
45
|
+
const setupHandler = (jobOptions?: { teamSize?: number }) => {
|
|
46
|
+
const instance = new TestHandler();
|
|
47
|
+
mockModulesContainer.set("TestModule", {
|
|
48
|
+
providers: new Map([["TestHandler", { instance }]]),
|
|
49
|
+
});
|
|
50
|
+
mockReflector.get.mockImplementation((key: string, target: any) => {
|
|
51
|
+
if (key === JOB_NAME && target === instance.handle) return "my-job";
|
|
52
|
+
if (key === JOB_OPTIONS && target === instance.handle)
|
|
53
|
+
return jobOptions;
|
|
54
|
+
return undefined;
|
|
55
|
+
});
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
it("should register job once by default", async () => {
|
|
59
|
+
setupHandler();
|
|
60
|
+
await service.scanAndRegisterHandlers();
|
|
61
|
+
expect(mockPgBossService.registerJob).toHaveBeenCalledTimes(1);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it("should register job multiple times when teamSize > 1", async () => {
|
|
65
|
+
setupHandler({ teamSize: 3 });
|
|
66
|
+
await service.scanAndRegisterHandlers();
|
|
67
|
+
expect(mockPgBossService.registerJob).toHaveBeenCalledTimes(3);
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it("should default to 1 when teamSize is 0", async () => {
|
|
71
|
+
setupHandler({ teamSize: 0 });
|
|
72
|
+
await service.scanAndRegisterHandlers();
|
|
73
|
+
expect(mockPgBossService.registerJob).toHaveBeenCalledTimes(1);
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it("should default to 1 when teamSize is negative", async () => {
|
|
77
|
+
setupHandler({ teamSize: -5 });
|
|
78
|
+
await service.scanAndRegisterHandlers();
|
|
79
|
+
expect(mockPgBossService.registerJob).toHaveBeenCalledTimes(1);
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
});
|