pp-command-bus 1.0.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/README.md +522 -0
- package/dist/command-bus/command-bus.spec.d.ts +1 -0
- package/dist/command-bus/command-bus.spec.js +398 -0
- package/dist/command-bus/command-bus.spec.js.map +1 -0
- package/dist/command-bus/command.d.ts +24 -0
- package/dist/command-bus/command.js +53 -0
- package/dist/command-bus/command.js.map +1 -0
- package/dist/command-bus/config/command-bus-config.d.ts +40 -0
- package/dist/command-bus/config/command-bus-config.js +59 -0
- package/dist/command-bus/config/command-bus-config.js.map +1 -0
- package/dist/command-bus/config/command-bus-config.spec.d.ts +1 -0
- package/dist/command-bus/config/command-bus-config.spec.js +162 -0
- package/dist/command-bus/config/command-bus-config.spec.js.map +1 -0
- package/dist/command-bus/config/index.d.ts +1 -0
- package/dist/command-bus/config/index.js +9 -0
- package/dist/command-bus/config/index.js.map +1 -0
- package/dist/command-bus/index.d.ts +79 -0
- package/dist/command-bus/index.js +169 -0
- package/dist/command-bus/index.js.map +1 -0
- package/dist/command-bus/job/index.d.ts +6 -0
- package/dist/command-bus/job/index.js +15 -0
- package/dist/command-bus/job/index.js.map +1 -0
- package/dist/command-bus/job/job-options-builder.d.ts +24 -0
- package/dist/command-bus/job/job-options-builder.js +68 -0
- package/dist/command-bus/job/job-options-builder.js.map +1 -0
- package/dist/command-bus/job/job-options-builder.spec.d.ts +1 -0
- package/dist/command-bus/job/job-options-builder.spec.js +163 -0
- package/dist/command-bus/job/job-options-builder.spec.js.map +1 -0
- package/dist/command-bus/job/job-processor.d.ts +33 -0
- package/dist/command-bus/job/job-processor.js +195 -0
- package/dist/command-bus/job/job-processor.js.map +1 -0
- package/dist/command-bus/job/job-processor.spec.d.ts +1 -0
- package/dist/command-bus/job/job-processor.spec.js +352 -0
- package/dist/command-bus/job/job-processor.spec.js.map +1 -0
- package/dist/command-bus/logging/command-logger.d.ts +21 -0
- package/dist/command-bus/logging/command-logger.js +79 -0
- package/dist/command-bus/logging/command-logger.js.map +1 -0
- package/dist/command-bus/logging/command-logger.spec.d.ts +1 -0
- package/dist/command-bus/logging/command-logger.spec.js +245 -0
- package/dist/command-bus/logging/command-logger.spec.js.map +1 -0
- package/dist/command-bus/logging/index.d.ts +5 -0
- package/dist/command-bus/logging/index.js +13 -0
- package/dist/command-bus/logging/index.js.map +1 -0
- package/dist/command-bus/queue/index.d.ts +5 -0
- package/dist/command-bus/queue/index.js +13 -0
- package/dist/command-bus/queue/index.js.map +1 -0
- package/dist/command-bus/queue/queue-manager.d.ts +24 -0
- package/dist/command-bus/queue/queue-manager.js +60 -0
- package/dist/command-bus/queue/queue-manager.js.map +1 -0
- package/dist/command-bus/queue/queue-manager.spec.d.ts +1 -0
- package/dist/command-bus/queue/queue-manager.spec.js +219 -0
- package/dist/command-bus/queue/queue-manager.spec.js.map +1 -0
- package/dist/command-bus/rpc/index.d.ts +5 -0
- package/dist/command-bus/rpc/index.js +13 -0
- package/dist/command-bus/rpc/index.js.map +1 -0
- package/dist/command-bus/rpc/rpc-coordinator.d.ts +45 -0
- package/dist/command-bus/rpc/rpc-coordinator.js +189 -0
- package/dist/command-bus/rpc/rpc-coordinator.js.map +1 -0
- package/dist/command-bus/rpc/rpc-coordinator.spec.d.ts +1 -0
- package/dist/command-bus/rpc/rpc-coordinator.spec.js +286 -0
- package/dist/command-bus/rpc/rpc-coordinator.spec.js.map +1 -0
- package/dist/command-bus/types/index.d.ts +57 -0
- package/dist/command-bus/types/index.js +3 -0
- package/dist/command-bus/types/index.js.map +1 -0
- package/dist/command-bus/worker/index.d.ts +5 -0
- package/dist/command-bus/worker/index.js +13 -0
- package/dist/command-bus/worker/index.js.map +1 -0
- package/dist/command-bus/worker/worker-orchestrator.d.ts +46 -0
- package/dist/command-bus/worker/worker-orchestrator.js +160 -0
- package/dist/command-bus/worker/worker-orchestrator.js.map +1 -0
- package/dist/command-bus/worker/worker-orchestrator.spec.d.ts +1 -0
- package/dist/command-bus/worker/worker-orchestrator.spec.js +293 -0
- package/dist/command-bus/worker/worker-orchestrator.spec.js.map +1 -0
- package/dist/examples/rpc.demo.d.ts +2 -0
- package/dist/examples/rpc.demo.js +235 -0
- package/dist/examples/rpc.demo.js.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.js +20 -0
- package/dist/index.js.map +1 -0
- package/dist/pp-command-bus-1.0.0.tgz +0 -0
- package/dist/shared/config/base-config.d.ts +43 -0
- package/dist/shared/config/base-config.js +100 -0
- package/dist/shared/config/base-config.js.map +1 -0
- package/dist/shared/config/base-config.spec.d.ts +1 -0
- package/dist/shared/config/base-config.spec.js +118 -0
- package/dist/shared/config/base-config.spec.js.map +1 -0
- package/dist/shared/config/index.d.ts +1 -0
- package/dist/shared/config/index.js +9 -0
- package/dist/shared/config/index.js.map +1 -0
- package/dist/shared/logging/index.d.ts +2 -0
- package/dist/shared/logging/index.js +8 -0
- package/dist/shared/logging/index.js.map +1 -0
- package/dist/shared/logging/log-level.d.ts +36 -0
- package/dist/shared/logging/log-level.js +53 -0
- package/dist/shared/logging/log-level.js.map +1 -0
- package/dist/shared/logging/logger.d.ts +42 -0
- package/dist/shared/logging/logger.js +63 -0
- package/dist/shared/logging/logger.js.map +1 -0
- package/dist/shared/logging/logger.spec.d.ts +1 -0
- package/dist/shared/logging/logger.spec.js +89 -0
- package/dist/shared/logging/logger.spec.js.map +1 -0
- package/dist/shared/types.d.ts +26 -0
- package/dist/shared/types.js +6 -0
- package/dist/shared/types.js.map +1 -0
- package/package.json +93 -0
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { Worker } from 'bullmq';
|
|
2
|
+
import type { Redis } from 'ioredis';
|
|
3
|
+
import type { ILogger } from '../../shared/types';
|
|
4
|
+
import type JobProcessor from '../job/job-processor';
|
|
5
|
+
/**
|
|
6
|
+
* Zarządza workerami BullMQ dla obsługi komend
|
|
7
|
+
*/
|
|
8
|
+
export default class WorkerOrchestrator {
|
|
9
|
+
private readonly redisConnection;
|
|
10
|
+
private readonly jobProcessor;
|
|
11
|
+
private readonly concurrency;
|
|
12
|
+
private readonly maxAttempts;
|
|
13
|
+
private readonly logger;
|
|
14
|
+
/**
|
|
15
|
+
* Workery BullMQ dla obsługi komend
|
|
16
|
+
*/
|
|
17
|
+
private workers;
|
|
18
|
+
constructor(redisConnection: Redis, jobProcessor: JobProcessor, concurrency: number, maxAttempts: number, logger: ILogger);
|
|
19
|
+
/**
|
|
20
|
+
* Rejestruje handler dla komendy i tworzy workera
|
|
21
|
+
* Reużywa własne Redis connection dla optymalizacji pamięci
|
|
22
|
+
* @param commandName - Nazwa komendy
|
|
23
|
+
*/
|
|
24
|
+
registerWorker(commandName: string): void;
|
|
25
|
+
/**
|
|
26
|
+
* Konfiguruje event handlery dla workera
|
|
27
|
+
* Memory optimization: redukcja captured variables w closures
|
|
28
|
+
*/
|
|
29
|
+
private setupWorkerEventHandlers;
|
|
30
|
+
/**
|
|
31
|
+
* Pobiera workera dla danego typu komendy
|
|
32
|
+
* @param commandName - Nazwa komendy
|
|
33
|
+
*/
|
|
34
|
+
getWorker(commandName: string): Worker | undefined;
|
|
35
|
+
/**
|
|
36
|
+
* Zamyka wszystkie workery
|
|
37
|
+
*/
|
|
38
|
+
closeAll(): Promise<void>;
|
|
39
|
+
/**
|
|
40
|
+
* Zwraca statystyki workerów (dla diagnostyki)
|
|
41
|
+
*/
|
|
42
|
+
getWorkerStats(): {
|
|
43
|
+
activeWorkersCount: number;
|
|
44
|
+
workerNames: string[];
|
|
45
|
+
};
|
|
46
|
+
}
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
const bullmq_1 = require("bullmq");
|
|
13
|
+
/**
|
|
14
|
+
* Zarządza workerami BullMQ dla obsługi komend
|
|
15
|
+
*/
|
|
16
|
+
class WorkerOrchestrator {
|
|
17
|
+
constructor(redisConnection, jobProcessor, concurrency, maxAttempts, logger) {
|
|
18
|
+
this.redisConnection = redisConnection;
|
|
19
|
+
this.jobProcessor = jobProcessor;
|
|
20
|
+
this.concurrency = concurrency;
|
|
21
|
+
this.maxAttempts = maxAttempts;
|
|
22
|
+
this.logger = logger;
|
|
23
|
+
/**
|
|
24
|
+
* Workery BullMQ dla obsługi komend
|
|
25
|
+
*/
|
|
26
|
+
this.workers = {};
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Rejestruje handler dla komendy i tworzy workera
|
|
30
|
+
* Reużywa własne Redis connection dla optymalizacji pamięci
|
|
31
|
+
* @param commandName - Nazwa komendy
|
|
32
|
+
*/
|
|
33
|
+
registerWorker(commandName) {
|
|
34
|
+
if (this.workers[commandName]) {
|
|
35
|
+
throw new Error(`Worker dla komendy ${commandName} już istnieje`);
|
|
36
|
+
}
|
|
37
|
+
this.workers[commandName] = new bullmq_1.Worker(`{${commandName}}`, (job) => __awaiter(this, void 0, void 0, function* () {
|
|
38
|
+
try {
|
|
39
|
+
return yield this.jobProcessor.process(job, commandName);
|
|
40
|
+
}
|
|
41
|
+
catch (error) {
|
|
42
|
+
// Top-level error boundary - zapobiega crashom workera
|
|
43
|
+
this.logger.error('Worker handler critical error', {
|
|
44
|
+
commandName,
|
|
45
|
+
jobId: job.id,
|
|
46
|
+
error: error instanceof Error ? error.message : String(error),
|
|
47
|
+
timestamp: new Date().toISOString(),
|
|
48
|
+
});
|
|
49
|
+
throw error; // BullMQ retry mechanism
|
|
50
|
+
}
|
|
51
|
+
}), {
|
|
52
|
+
connection: this.redisConnection,
|
|
53
|
+
concurrency: this.concurrency,
|
|
54
|
+
});
|
|
55
|
+
this.setupWorkerEventHandlers(commandName);
|
|
56
|
+
this.logger.log(`Worker zarejestrowany dla komendy ${commandName}`, {
|
|
57
|
+
concurrency: this.concurrency,
|
|
58
|
+
timestamp: new Date().toISOString(),
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Konfiguruje event handlery dla workera
|
|
63
|
+
* Memory optimization: redukcja captured variables w closures
|
|
64
|
+
*/
|
|
65
|
+
setupWorkerEventHandlers(commandName) {
|
|
66
|
+
const worker = this.workers[commandName];
|
|
67
|
+
const logger = this.logger;
|
|
68
|
+
const maxAttempts = this.maxAttempts;
|
|
69
|
+
worker.on('failed', (job, err) => {
|
|
70
|
+
var _a, _b, _c, _d, _e;
|
|
71
|
+
const command = job === null || job === void 0 ? void 0 : job.data;
|
|
72
|
+
logger.error('Job zakończony niepowodzeniem', {
|
|
73
|
+
commandName,
|
|
74
|
+
commandId: command === null || command === void 0 ? void 0 : command.__id,
|
|
75
|
+
jobId: job === null || job === void 0 ? void 0 : job.id,
|
|
76
|
+
error: err.message,
|
|
77
|
+
attempt: job === null || job === void 0 ? void 0 : job.attemptsMade,
|
|
78
|
+
maxAttempts: (_b = (_a = job === null || job === void 0 ? void 0 : job.opts) === null || _a === void 0 ? void 0 : _a.attempts) !== null && _b !== void 0 ? _b : maxAttempts,
|
|
79
|
+
isRetryable: ((_c = job === null || job === void 0 ? void 0 : job.attemptsMade) !== null && _c !== void 0 ? _c : 0) < ((_e = (_d = job === null || job === void 0 ? void 0 : job.opts) === null || _d === void 0 ? void 0 : _d.attempts) !== null && _e !== void 0 ? _e : maxAttempts),
|
|
80
|
+
timestamp: new Date().toISOString(),
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
worker.on('completed', (job) => {
|
|
84
|
+
const command = job === null || job === void 0 ? void 0 : job.data;
|
|
85
|
+
logger.log('Job zakończony pomyślnie', {
|
|
86
|
+
commandName,
|
|
87
|
+
commandId: command === null || command === void 0 ? void 0 : command.__id,
|
|
88
|
+
jobId: job.id,
|
|
89
|
+
hasReturnValue: job.returnvalue !== undefined,
|
|
90
|
+
timestamp: new Date().toISOString(),
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
worker.on('active', (job) => {
|
|
94
|
+
const command = job === null || job === void 0 ? void 0 : job.data;
|
|
95
|
+
logger.debug('Job rozpoczęty', {
|
|
96
|
+
commandName,
|
|
97
|
+
commandId: command === null || command === void 0 ? void 0 : command.__id,
|
|
98
|
+
jobId: job.id,
|
|
99
|
+
timestamp: new Date().toISOString(),
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
worker.on('stalled', (jobId) => {
|
|
103
|
+
logger.warn('Job zatrzymany (stalled)', {
|
|
104
|
+
commandName,
|
|
105
|
+
jobId,
|
|
106
|
+
reason: 'Prawdopodobnie worker przestał odpowiadać',
|
|
107
|
+
timestamp: new Date().toISOString(),
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
worker.on('progress', (job, progress) => {
|
|
111
|
+
const command = job === null || job === void 0 ? void 0 : job.data;
|
|
112
|
+
logger.debug('Job - postęp przetwarzania', {
|
|
113
|
+
commandName,
|
|
114
|
+
commandId: command === null || command === void 0 ? void 0 : command.__id,
|
|
115
|
+
jobId: job.id,
|
|
116
|
+
progress,
|
|
117
|
+
timestamp: new Date().toISOString(),
|
|
118
|
+
});
|
|
119
|
+
});
|
|
120
|
+
worker.on('error', (err) => {
|
|
121
|
+
logger.error('Błąd workera', {
|
|
122
|
+
commandName,
|
|
123
|
+
error: err.message,
|
|
124
|
+
timestamp: new Date().toISOString(),
|
|
125
|
+
});
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Pobiera workera dla danego typu komendy
|
|
130
|
+
* @param commandName - Nazwa komendy
|
|
131
|
+
*/
|
|
132
|
+
getWorker(commandName) {
|
|
133
|
+
return this.workers[commandName];
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Zamyka wszystkie workery
|
|
137
|
+
*/
|
|
138
|
+
closeAll() {
|
|
139
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
140
|
+
const workers = Object.values(this.workers);
|
|
141
|
+
// Usuń wszystkie event listeners PRZED zamknięciem workerów
|
|
142
|
+
// Zapobiega memory leakom z closures i referencjami do handlery
|
|
143
|
+
workers.forEach((worker) => worker.removeAllListeners());
|
|
144
|
+
// Zamknij workery
|
|
145
|
+
yield Promise.all(workers.map((worker) => worker.close()));
|
|
146
|
+
this.workers = {};
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Zwraca statystyki workerów (dla diagnostyki)
|
|
151
|
+
*/
|
|
152
|
+
getWorkerStats() {
|
|
153
|
+
return {
|
|
154
|
+
activeWorkersCount: Object.keys(this.workers).length,
|
|
155
|
+
workerNames: Object.keys(this.workers),
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
exports.default = WorkerOrchestrator;
|
|
160
|
+
//# sourceMappingURL=worker-orchestrator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worker-orchestrator.js","sourceRoot":"","sources":["../../../src/command-bus/worker/worker-orchestrator.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
const bullmq_1 = require("bullmq");
|
|
16
|
+
const worker_orchestrator_1 = __importDefault(require("./worker-orchestrator"));
|
|
17
|
+
// Mock BullMQ
|
|
18
|
+
jest.mock('bullmq');
|
|
19
|
+
describe('WorkerOrchestrator', () => {
|
|
20
|
+
let workerOrchestrator;
|
|
21
|
+
let mockRedisConnection;
|
|
22
|
+
let mockJobProcessor;
|
|
23
|
+
let mockLogger;
|
|
24
|
+
let mockWorker;
|
|
25
|
+
const concurrency = 5;
|
|
26
|
+
const maxAttempts = 3;
|
|
27
|
+
beforeEach(() => {
|
|
28
|
+
jest.clearAllMocks();
|
|
29
|
+
mockLogger = {
|
|
30
|
+
log: jest.fn(),
|
|
31
|
+
error: jest.fn(),
|
|
32
|
+
warn: jest.fn(),
|
|
33
|
+
debug: jest.fn(),
|
|
34
|
+
};
|
|
35
|
+
// Mock Redis connection - przekazywany przez DI
|
|
36
|
+
mockRedisConnection = {};
|
|
37
|
+
mockJobProcessor = {
|
|
38
|
+
process: jest.fn().mockResolvedValue({ success: true }),
|
|
39
|
+
};
|
|
40
|
+
// Mock Worker
|
|
41
|
+
mockWorker = {
|
|
42
|
+
close: jest.fn().mockResolvedValue(undefined),
|
|
43
|
+
on: jest.fn().mockReturnThis(),
|
|
44
|
+
removeAllListeners: jest.fn().mockReturnThis(),
|
|
45
|
+
};
|
|
46
|
+
bullmq_1.Worker.mockImplementation(() => mockWorker);
|
|
47
|
+
workerOrchestrator = new worker_orchestrator_1.default(mockRedisConnection, mockJobProcessor, concurrency, maxAttempts, mockLogger);
|
|
48
|
+
});
|
|
49
|
+
describe('registerWorker', () => {
|
|
50
|
+
it('powinno utworzyć nowy worker dla komendy', () => {
|
|
51
|
+
// Given
|
|
52
|
+
const commandName = 'TestCommand';
|
|
53
|
+
// When
|
|
54
|
+
workerOrchestrator.registerWorker(commandName);
|
|
55
|
+
// Then
|
|
56
|
+
expect(bullmq_1.Worker).toHaveBeenCalledWith(`{${commandName}}`, expect.any(Function), expect.objectContaining({
|
|
57
|
+
connection: mockRedisConnection,
|
|
58
|
+
concurrency,
|
|
59
|
+
}));
|
|
60
|
+
expect(mockLogger.log).toHaveBeenCalledWith(`Worker zarejestrowany dla komendy ${commandName}`, expect.objectContaining({
|
|
61
|
+
concurrency,
|
|
62
|
+
}));
|
|
63
|
+
});
|
|
64
|
+
it('powinno rzucić błąd gdy worker już istnieje dla komendy', () => {
|
|
65
|
+
// Given
|
|
66
|
+
const commandName = 'TestCommand';
|
|
67
|
+
workerOrchestrator.registerWorker(commandName);
|
|
68
|
+
// When & Then
|
|
69
|
+
expect(() => workerOrchestrator.registerWorker(commandName)).toThrow(`Worker dla komendy ${commandName} już istnieje`);
|
|
70
|
+
});
|
|
71
|
+
it('powinno skonfigurować event handlery dla workera', () => {
|
|
72
|
+
// Given
|
|
73
|
+
const commandName = 'TestCommand';
|
|
74
|
+
// When
|
|
75
|
+
workerOrchestrator.registerWorker(commandName);
|
|
76
|
+
// Then
|
|
77
|
+
expect(mockWorker.on).toHaveBeenCalledWith('failed', expect.any(Function));
|
|
78
|
+
expect(mockWorker.on).toHaveBeenCalledWith('completed', expect.any(Function));
|
|
79
|
+
expect(mockWorker.on).toHaveBeenCalledWith('active', expect.any(Function));
|
|
80
|
+
expect(mockWorker.on).toHaveBeenCalledWith('stalled', expect.any(Function));
|
|
81
|
+
expect(mockWorker.on).toHaveBeenCalledWith('progress', expect.any(Function));
|
|
82
|
+
expect(mockWorker.on).toHaveBeenCalledWith('error', expect.any(Function));
|
|
83
|
+
});
|
|
84
|
+
it("powinno wywołać jobProcessor.process w handler'ze workera", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
85
|
+
// Given
|
|
86
|
+
const commandName = 'TestCommand';
|
|
87
|
+
workerOrchestrator.registerWorker(commandName);
|
|
88
|
+
const workerCalls = bullmq_1.Worker.mock.calls;
|
|
89
|
+
const jobHandler = workerCalls[0][1];
|
|
90
|
+
const mockJob = {
|
|
91
|
+
id: 'job-123',
|
|
92
|
+
data: { __id: 'cmd-123' },
|
|
93
|
+
};
|
|
94
|
+
// When
|
|
95
|
+
yield jobHandler(mockJob);
|
|
96
|
+
// Then
|
|
97
|
+
expect(mockJobProcessor.process).toHaveBeenCalledWith(mockJob, commandName);
|
|
98
|
+
}));
|
|
99
|
+
it('powinno propagować błędy z jobProcessor dla BullMQ retry', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
100
|
+
// Given
|
|
101
|
+
const commandName = 'TestCommand';
|
|
102
|
+
const processorError = new Error('Processor error');
|
|
103
|
+
mockJobProcessor.process.mockRejectedValueOnce(processorError);
|
|
104
|
+
workerOrchestrator.registerWorker(commandName);
|
|
105
|
+
const workerCalls = bullmq_1.Worker.mock.calls;
|
|
106
|
+
const jobHandler = workerCalls[0][1];
|
|
107
|
+
const mockJob = {
|
|
108
|
+
id: 'job-123',
|
|
109
|
+
data: { __id: 'cmd-123' },
|
|
110
|
+
};
|
|
111
|
+
// When & Then
|
|
112
|
+
yield expect(jobHandler(mockJob)).rejects.toThrow('Processor error');
|
|
113
|
+
expect(mockLogger.error).toHaveBeenCalledWith('Worker handler critical error', expect.objectContaining({
|
|
114
|
+
commandName,
|
|
115
|
+
jobId: 'job-123',
|
|
116
|
+
error: 'Processor error',
|
|
117
|
+
}));
|
|
118
|
+
}));
|
|
119
|
+
});
|
|
120
|
+
describe('setupWorkerEventHandlers', () => {
|
|
121
|
+
it("powinno zalogować event 'failed'", () => {
|
|
122
|
+
// Given
|
|
123
|
+
const commandName = 'TestCommand';
|
|
124
|
+
workerOrchestrator.registerWorker(commandName);
|
|
125
|
+
const failedHandler = mockWorker.on.mock.calls.find((call) => call[0] === 'failed')[1];
|
|
126
|
+
const mockJob = {
|
|
127
|
+
id: 'job-123',
|
|
128
|
+
data: { __id: 'cmd-123' },
|
|
129
|
+
attemptsMade: 2,
|
|
130
|
+
opts: { attempts: maxAttempts },
|
|
131
|
+
};
|
|
132
|
+
const error = new Error('Job failed');
|
|
133
|
+
// When
|
|
134
|
+
failedHandler(mockJob, error);
|
|
135
|
+
// Then
|
|
136
|
+
expect(mockLogger.error).toHaveBeenCalledWith('Job zakończony niepowodzeniem', expect.objectContaining({
|
|
137
|
+
commandName,
|
|
138
|
+
jobId: 'job-123',
|
|
139
|
+
error: 'Job failed',
|
|
140
|
+
attempt: 2,
|
|
141
|
+
maxAttempts,
|
|
142
|
+
isRetryable: true,
|
|
143
|
+
}));
|
|
144
|
+
});
|
|
145
|
+
it("powinno zalogować event 'completed'", () => {
|
|
146
|
+
// Given
|
|
147
|
+
const commandName = 'TestCommand';
|
|
148
|
+
workerOrchestrator.registerWorker(commandName);
|
|
149
|
+
const completedHandler = mockWorker.on.mock.calls.find((call) => call[0] === 'completed')[1];
|
|
150
|
+
const mockJob = {
|
|
151
|
+
id: 'job-123',
|
|
152
|
+
data: { __id: 'cmd-123' },
|
|
153
|
+
returnvalue: { success: true },
|
|
154
|
+
};
|
|
155
|
+
// When
|
|
156
|
+
completedHandler(mockJob);
|
|
157
|
+
// Then
|
|
158
|
+
expect(mockLogger.log).toHaveBeenCalledWith('Job zakończony pomyślnie', expect.objectContaining({
|
|
159
|
+
commandName,
|
|
160
|
+
jobId: 'job-123',
|
|
161
|
+
hasReturnValue: true,
|
|
162
|
+
}));
|
|
163
|
+
});
|
|
164
|
+
it("powinno zalogować event 'active'", () => {
|
|
165
|
+
// Given
|
|
166
|
+
const commandName = 'TestCommand';
|
|
167
|
+
workerOrchestrator.registerWorker(commandName);
|
|
168
|
+
const activeHandler = mockWorker.on.mock.calls.find((call) => call[0] === 'active')[1];
|
|
169
|
+
const mockJob = {
|
|
170
|
+
id: 'job-123',
|
|
171
|
+
data: { __id: 'cmd-123' },
|
|
172
|
+
};
|
|
173
|
+
// When
|
|
174
|
+
activeHandler(mockJob);
|
|
175
|
+
// Then
|
|
176
|
+
expect(mockLogger.debug).toHaveBeenCalledWith('Job rozpoczęty', expect.objectContaining({
|
|
177
|
+
commandName,
|
|
178
|
+
jobId: 'job-123',
|
|
179
|
+
}));
|
|
180
|
+
});
|
|
181
|
+
it("powinno zalogować event 'stalled'", () => {
|
|
182
|
+
// Given
|
|
183
|
+
const commandName = 'TestCommand';
|
|
184
|
+
workerOrchestrator.registerWorker(commandName);
|
|
185
|
+
const stalledHandler = mockWorker.on.mock.calls.find((call) => call[0] === 'stalled')[1];
|
|
186
|
+
const jobId = 'job-123';
|
|
187
|
+
// When
|
|
188
|
+
stalledHandler(jobId);
|
|
189
|
+
// Then
|
|
190
|
+
expect(mockLogger.warn).toHaveBeenCalledWith('Job zatrzymany (stalled)', expect.objectContaining({
|
|
191
|
+
commandName,
|
|
192
|
+
jobId,
|
|
193
|
+
reason: 'Prawdopodobnie worker przestał odpowiadać',
|
|
194
|
+
}));
|
|
195
|
+
});
|
|
196
|
+
it("powinno zalogować event 'progress'", () => {
|
|
197
|
+
// Given
|
|
198
|
+
const commandName = 'TestCommand';
|
|
199
|
+
workerOrchestrator.registerWorker(commandName);
|
|
200
|
+
const progressHandler = mockWorker.on.mock.calls.find((call) => call[0] === 'progress')[1];
|
|
201
|
+
const mockJob = {
|
|
202
|
+
id: 'job-123',
|
|
203
|
+
data: { __id: 'cmd-123' },
|
|
204
|
+
};
|
|
205
|
+
const progress = 50;
|
|
206
|
+
// When
|
|
207
|
+
progressHandler(mockJob, progress);
|
|
208
|
+
// Then
|
|
209
|
+
expect(mockLogger.debug).toHaveBeenCalledWith('Job - postęp przetwarzania', expect.objectContaining({
|
|
210
|
+
commandName,
|
|
211
|
+
jobId: 'job-123',
|
|
212
|
+
progress: 50,
|
|
213
|
+
}));
|
|
214
|
+
});
|
|
215
|
+
it("powinno zalogować event 'error'", () => {
|
|
216
|
+
// Given
|
|
217
|
+
const commandName = 'TestCommand';
|
|
218
|
+
workerOrchestrator.registerWorker(commandName);
|
|
219
|
+
const errorHandler = mockWorker.on.mock.calls.find((call) => call[0] === 'error')[1];
|
|
220
|
+
const error = new Error('Worker error');
|
|
221
|
+
// When
|
|
222
|
+
errorHandler(error);
|
|
223
|
+
// Then
|
|
224
|
+
expect(mockLogger.error).toHaveBeenCalledWith('Błąd workera', expect.objectContaining({
|
|
225
|
+
commandName,
|
|
226
|
+
error: 'Worker error',
|
|
227
|
+
}));
|
|
228
|
+
});
|
|
229
|
+
it('powinno obsłużyć brak attempt info w failed event', () => {
|
|
230
|
+
// Given
|
|
231
|
+
const commandName = 'TestCommand';
|
|
232
|
+
workerOrchestrator.registerWorker(commandName);
|
|
233
|
+
const failedHandler = mockWorker.on.mock.calls.find((call) => call[0] === 'failed')[1];
|
|
234
|
+
const mockJob = {
|
|
235
|
+
id: 'job-123',
|
|
236
|
+
data: { __id: 'cmd-123' },
|
|
237
|
+
// Brak attemptsMade i opts
|
|
238
|
+
};
|
|
239
|
+
const error = new Error('Job failed');
|
|
240
|
+
// When
|
|
241
|
+
failedHandler(mockJob, error);
|
|
242
|
+
// Then
|
|
243
|
+
expect(mockLogger.error).toHaveBeenCalledWith('Job zakończony niepowodzeniem', expect.objectContaining({
|
|
244
|
+
attempt: undefined, // attemptsMade jest undefined gdy nie ma tej właściwości
|
|
245
|
+
maxAttempts,
|
|
246
|
+
isRetryable: true, // (0 || 0) < maxAttempts = true
|
|
247
|
+
}));
|
|
248
|
+
});
|
|
249
|
+
});
|
|
250
|
+
describe('getWorker', () => {
|
|
251
|
+
it('powinno zwrócić workera dla komendy', () => {
|
|
252
|
+
// Given
|
|
253
|
+
const commandName = 'TestCommand';
|
|
254
|
+
workerOrchestrator.registerWorker(commandName);
|
|
255
|
+
// When
|
|
256
|
+
const worker = workerOrchestrator.getWorker(commandName);
|
|
257
|
+
// Then
|
|
258
|
+
expect(worker).toBe(mockWorker);
|
|
259
|
+
});
|
|
260
|
+
it('powinno zwrócić undefined dla niezarejestrowanego workera', () => {
|
|
261
|
+
// When
|
|
262
|
+
const worker = workerOrchestrator.getWorker('NonExistentCommand');
|
|
263
|
+
// Then
|
|
264
|
+
expect(worker).toBeUndefined();
|
|
265
|
+
});
|
|
266
|
+
});
|
|
267
|
+
describe('closeAll', () => {
|
|
268
|
+
it('powinno zamknąć wszystkich workerów', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
269
|
+
// Given
|
|
270
|
+
workerOrchestrator.registerWorker('TestCommand1');
|
|
271
|
+
workerOrchestrator.registerWorker('TestCommand2');
|
|
272
|
+
workerOrchestrator.registerWorker('TestCommand3');
|
|
273
|
+
// When
|
|
274
|
+
yield workerOrchestrator.closeAll();
|
|
275
|
+
// Then
|
|
276
|
+
expect(mockWorker.close).toHaveBeenCalledTimes(3);
|
|
277
|
+
}));
|
|
278
|
+
it('powinno wyczyścić cache workerów', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
279
|
+
// Given
|
|
280
|
+
workerOrchestrator.registerWorker('TestCommand');
|
|
281
|
+
yield workerOrchestrator.closeAll();
|
|
282
|
+
// When
|
|
283
|
+
const worker = workerOrchestrator.getWorker('TestCommand');
|
|
284
|
+
// Then
|
|
285
|
+
expect(worker).toBeUndefined();
|
|
286
|
+
}));
|
|
287
|
+
it('powinno działać gdy brak workerów', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
288
|
+
// When & Then
|
|
289
|
+
yield expect(workerOrchestrator.closeAll()).resolves.toBeUndefined();
|
|
290
|
+
}));
|
|
291
|
+
});
|
|
292
|
+
});
|
|
293
|
+
//# sourceMappingURL=worker-orchestrator.spec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worker-orchestrator.spec.js","sourceRoot":"","sources":["../../../src/command-bus/worker/worker-orchestrator.spec.ts"],"names":[],"mappings":"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"}
|