pp-command-bus 1.0.2 → 1.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/command-bus/command-bus.spec.js +26 -8
- package/dist/command-bus/command-bus.spec.js.map +1 -1
- package/dist/command-bus/config/auto-config-optimizer.d.ts +35 -0
- package/dist/command-bus/config/auto-config-optimizer.js +52 -0
- package/dist/command-bus/config/auto-config-optimizer.js.map +1 -0
- package/dist/command-bus/config/auto-config-optimizer.spec.d.ts +1 -0
- package/dist/command-bus/config/auto-config-optimizer.spec.js +42 -0
- package/dist/command-bus/config/auto-config-optimizer.spec.js.map +1 -0
- package/dist/command-bus/config/command-bus-config.d.ts +6 -0
- package/dist/command-bus/config/command-bus-config.js +33 -6
- package/dist/command-bus/config/command-bus-config.js.map +1 -1
- package/dist/command-bus/config/command-bus-config.spec.js +62 -2
- package/dist/command-bus/config/command-bus-config.spec.js.map +1 -1
- package/dist/command-bus/index.d.ts +4 -0
- package/dist/command-bus/index.js +21 -6
- package/dist/command-bus/index.js.map +1 -1
- package/dist/command-bus/job/job-processor.d.ts +2 -0
- package/dist/command-bus/job/job-processor.js +50 -2
- package/dist/command-bus/job/job-processor.js.map +1 -1
- package/dist/command-bus/job/job-processor.spec.js +13 -0
- package/dist/command-bus/job/job-processor.spec.js.map +1 -1
- package/dist/command-bus/queue/queue-manager.d.ts +35 -3
- package/dist/command-bus/queue/queue-manager.js +107 -4
- package/dist/command-bus/queue/queue-manager.js.map +1 -1
- package/dist/command-bus/queue/queue-manager.spec.js +155 -3
- package/dist/command-bus/queue/queue-manager.spec.js.map +1 -1
- package/dist/command-bus/rpc/rpc-coordinator.js +6 -1
- package/dist/command-bus/rpc/rpc-coordinator.js.map +1 -1
- package/dist/command-bus/rpc/rpc-coordinator.spec.js +211 -0
- package/dist/command-bus/rpc/rpc-coordinator.spec.js.map +1 -1
- package/dist/command-bus/worker/index.d.ts +6 -1
- package/dist/command-bus/worker/index.js +8 -2
- package/dist/command-bus/worker/index.js.map +1 -1
- package/dist/command-bus/worker/worker-benchmark.d.ts +70 -0
- package/dist/command-bus/worker/worker-benchmark.js +210 -0
- package/dist/command-bus/worker/worker-benchmark.js.map +1 -0
- package/dist/command-bus/worker/worker-benchmark.spec.d.ts +1 -0
- package/dist/command-bus/worker/worker-benchmark.spec.js +300 -0
- package/dist/command-bus/worker/worker-benchmark.spec.js.map +1 -0
- package/dist/command-bus/worker/worker-metrics-collector.d.ts +87 -0
- package/dist/command-bus/worker/worker-metrics-collector.js +259 -0
- package/dist/command-bus/worker/worker-metrics-collector.js.map +1 -0
- package/dist/command-bus/worker/worker-metrics-collector.spec.d.ts +1 -0
- package/dist/command-bus/worker/worker-metrics-collector.spec.js +315 -0
- package/dist/command-bus/worker/worker-metrics-collector.spec.js.map +1 -0
- package/dist/command-bus/worker/worker-orchestrator.d.ts +29 -4
- package/dist/command-bus/worker/worker-orchestrator.js +198 -27
- package/dist/command-bus/worker/worker-orchestrator.js.map +1 -1
- package/dist/command-bus/worker/worker-orchestrator.spec.js +473 -52
- package/dist/command-bus/worker/worker-orchestrator.spec.js.map +1 -1
- package/dist/examples/auto-config.demo.d.ts +9 -0
- package/dist/examples/auto-config.demo.js +106 -0
- package/dist/examples/auto-config.demo.js.map +1 -0
- package/dist/examples/rpc-throughput.demo.d.ts +5 -0
- package/dist/examples/rpc-throughput.demo.js +326 -0
- package/dist/examples/rpc-throughput.demo.js.map +1 -0
- package/dist/pp-command-bus-1.1.0.tgz +0 -0
- package/package.json +3 -2
- package/dist/pp-command-bus-1.0.2.tgz +0 -0
|
@@ -16,16 +16,38 @@ const bullmq_1 = require("bullmq");
|
|
|
16
16
|
const worker_orchestrator_1 = __importDefault(require("./worker-orchestrator"));
|
|
17
17
|
// Mock BullMQ
|
|
18
18
|
jest.mock('bullmq');
|
|
19
|
+
// Mock WorkerBenchmark
|
|
20
|
+
jest.mock('./worker-benchmark', () => {
|
|
21
|
+
return jest.fn().mockImplementation(() => ({
|
|
22
|
+
run: jest.fn().mockResolvedValue({
|
|
23
|
+
recommendedConcurrency: 5,
|
|
24
|
+
jobsPerSecond: 100,
|
|
25
|
+
avgProcessingTime: 10,
|
|
26
|
+
}),
|
|
27
|
+
}));
|
|
28
|
+
});
|
|
29
|
+
// Mock WorkerMetricsCollector
|
|
30
|
+
jest.mock('./worker-metrics-collector', () => {
|
|
31
|
+
return jest.fn().mockImplementation(() => ({
|
|
32
|
+
start: jest.fn(),
|
|
33
|
+
stop: jest.fn(),
|
|
34
|
+
recordJobProcessingTime: jest.fn(),
|
|
35
|
+
}));
|
|
36
|
+
});
|
|
19
37
|
describe('WorkerOrchestrator', () => {
|
|
20
38
|
let workerOrchestrator;
|
|
21
39
|
let mockRedisConnection;
|
|
22
40
|
let mockJobProcessor;
|
|
41
|
+
let mockQueueManager;
|
|
23
42
|
let mockLogger;
|
|
24
43
|
let mockWorker;
|
|
25
44
|
const concurrency = 5;
|
|
26
45
|
const maxAttempts = 3;
|
|
46
|
+
// Storage dla concurrency każdego workera
|
|
47
|
+
const workerConcurrencyStorage = new Map();
|
|
27
48
|
beforeEach(() => {
|
|
28
49
|
jest.clearAllMocks();
|
|
50
|
+
workerConcurrencyStorage.clear();
|
|
29
51
|
mockLogger = {
|
|
30
52
|
log: jest.fn(),
|
|
31
53
|
error: jest.fn(),
|
|
@@ -37,42 +59,64 @@ describe('WorkerOrchestrator', () => {
|
|
|
37
59
|
mockJobProcessor = {
|
|
38
60
|
process: jest.fn().mockResolvedValue({ success: true }),
|
|
39
61
|
};
|
|
40
|
-
// Mock
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
62
|
+
// Mock QueueManager
|
|
63
|
+
mockQueueManager = {
|
|
64
|
+
getOrCreateQueue: jest.fn().mockReturnValue({
|
|
65
|
+
name: 'test-queue',
|
|
66
|
+
}),
|
|
45
67
|
};
|
|
46
|
-
|
|
47
|
-
|
|
68
|
+
// Mock Worker factory z concurrency property per-instance
|
|
69
|
+
bullmq_1.Worker.mockImplementation((_queueName, _processor, options) => {
|
|
70
|
+
var _a;
|
|
71
|
+
const workerInstance = {
|
|
72
|
+
close: jest.fn().mockResolvedValue(undefined),
|
|
73
|
+
on: jest.fn().mockReturnThis(),
|
|
74
|
+
removeAllListeners: jest.fn().mockReturnThis(),
|
|
75
|
+
get concurrency() {
|
|
76
|
+
var _a;
|
|
77
|
+
return (_a = workerConcurrencyStorage.get(workerInstance)) !== null && _a !== void 0 ? _a : 5;
|
|
78
|
+
},
|
|
79
|
+
set concurrency(value) {
|
|
80
|
+
workerConcurrencyStorage.set(workerInstance, value);
|
|
81
|
+
},
|
|
82
|
+
};
|
|
83
|
+
// Ustaw początkową wartość z opcji lub domyślnie 5
|
|
84
|
+
const initialConcurrency = (_a = options === null || options === void 0 ? void 0 : options.concurrency) !== null && _a !== void 0 ? _a : 5;
|
|
85
|
+
workerConcurrencyStorage.set(workerInstance, initialConcurrency);
|
|
86
|
+
mockWorker = workerInstance;
|
|
87
|
+
return workerInstance;
|
|
88
|
+
});
|
|
89
|
+
workerOrchestrator = new worker_orchestrator_1.default(mockRedisConnection, mockJobProcessor, mockQueueManager, concurrency, maxAttempts, mockLogger);
|
|
48
90
|
});
|
|
49
91
|
describe('registerWorker', () => {
|
|
50
|
-
it('powinno utworzyć nowy worker dla komendy', () => {
|
|
92
|
+
it('powinno utworzyć nowy worker dla komendy', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
51
93
|
// Given
|
|
52
94
|
const commandName = 'TestCommand';
|
|
53
95
|
// When
|
|
54
|
-
workerOrchestrator.registerWorker(commandName);
|
|
96
|
+
yield workerOrchestrator.registerWorker(commandName);
|
|
55
97
|
// Then
|
|
56
98
|
expect(bullmq_1.Worker).toHaveBeenCalledWith(`{${commandName}}`, expect.any(Function), expect.objectContaining({
|
|
57
99
|
connection: mockRedisConnection,
|
|
58
|
-
concurrency,
|
|
100
|
+
concurrency: 5, // Z benchmark result
|
|
59
101
|
}));
|
|
60
|
-
expect(mockLogger.log).toHaveBeenCalledWith(
|
|
61
|
-
|
|
102
|
+
expect(mockLogger.log).toHaveBeenCalledWith('Benchmark zakończony - tworzę workera', expect.objectContaining({
|
|
103
|
+
commandName,
|
|
104
|
+
oldConcurrency: concurrency,
|
|
105
|
+
newConcurrency: 5,
|
|
62
106
|
}));
|
|
63
|
-
});
|
|
64
|
-
it('powinno rzucić błąd gdy worker już istnieje dla komendy', () => {
|
|
107
|
+
}));
|
|
108
|
+
it('powinno rzucić błąd gdy worker już istnieje dla komendy', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
65
109
|
// Given
|
|
66
110
|
const commandName = 'TestCommand';
|
|
67
|
-
workerOrchestrator.registerWorker(commandName);
|
|
111
|
+
yield workerOrchestrator.registerWorker(commandName);
|
|
68
112
|
// When & Then
|
|
69
|
-
expect(
|
|
70
|
-
});
|
|
71
|
-
it('powinno skonfigurować event handlery dla workera', () => {
|
|
113
|
+
yield expect(workerOrchestrator.registerWorker(commandName)).rejects.toThrow(`Worker dla komendy ${commandName} już istnieje`);
|
|
114
|
+
}));
|
|
115
|
+
it('powinno skonfigurować event handlery dla workera', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
72
116
|
// Given
|
|
73
117
|
const commandName = 'TestCommand';
|
|
74
118
|
// When
|
|
75
|
-
workerOrchestrator.registerWorker(commandName);
|
|
119
|
+
yield workerOrchestrator.registerWorker(commandName);
|
|
76
120
|
// Then
|
|
77
121
|
expect(mockWorker.on).toHaveBeenCalledWith('failed', expect.any(Function));
|
|
78
122
|
expect(mockWorker.on).toHaveBeenCalledWith('completed', expect.any(Function));
|
|
@@ -80,11 +124,11 @@ describe('WorkerOrchestrator', () => {
|
|
|
80
124
|
expect(mockWorker.on).toHaveBeenCalledWith('stalled', expect.any(Function));
|
|
81
125
|
expect(mockWorker.on).toHaveBeenCalledWith('progress', expect.any(Function));
|
|
82
126
|
expect(mockWorker.on).toHaveBeenCalledWith('error', expect.any(Function));
|
|
83
|
-
});
|
|
127
|
+
}));
|
|
84
128
|
it("powinno wywołać jobProcessor.process w handler'ze workera", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
85
129
|
// Given
|
|
86
130
|
const commandName = 'TestCommand';
|
|
87
|
-
workerOrchestrator.registerWorker(commandName);
|
|
131
|
+
yield workerOrchestrator.registerWorker(commandName);
|
|
88
132
|
const workerCalls = bullmq_1.Worker.mock.calls;
|
|
89
133
|
const jobHandler = workerCalls[0][1];
|
|
90
134
|
const mockJob = {
|
|
@@ -101,7 +145,7 @@ describe('WorkerOrchestrator', () => {
|
|
|
101
145
|
const commandName = 'TestCommand';
|
|
102
146
|
const processorError = new Error('Processor error');
|
|
103
147
|
mockJobProcessor.process.mockRejectedValueOnce(processorError);
|
|
104
|
-
workerOrchestrator.registerWorker(commandName);
|
|
148
|
+
yield workerOrchestrator.registerWorker(commandName);
|
|
105
149
|
const workerCalls = bullmq_1.Worker.mock.calls;
|
|
106
150
|
const jobHandler = workerCalls[0][1];
|
|
107
151
|
const mockJob = {
|
|
@@ -118,10 +162,10 @@ describe('WorkerOrchestrator', () => {
|
|
|
118
162
|
}));
|
|
119
163
|
});
|
|
120
164
|
describe('setupWorkerEventHandlers', () => {
|
|
121
|
-
it("powinno zalogować event 'failed'", () => {
|
|
165
|
+
it("powinno zalogować event 'failed'", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
122
166
|
// Given
|
|
123
167
|
const commandName = 'TestCommand';
|
|
124
|
-
workerOrchestrator.registerWorker(commandName);
|
|
168
|
+
yield workerOrchestrator.registerWorker(commandName);
|
|
125
169
|
const failedHandler = mockWorker.on.mock.calls.find((call) => call[0] === 'failed')[1];
|
|
126
170
|
const mockJob = {
|
|
127
171
|
id: 'job-123',
|
|
@@ -141,11 +185,11 @@ describe('WorkerOrchestrator', () => {
|
|
|
141
185
|
maxAttempts,
|
|
142
186
|
isRetryable: true,
|
|
143
187
|
}));
|
|
144
|
-
});
|
|
145
|
-
it("powinno zalogować event 'completed'", () => {
|
|
188
|
+
}));
|
|
189
|
+
it("powinno zalogować event 'completed'", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
146
190
|
// Given
|
|
147
191
|
const commandName = 'TestCommand';
|
|
148
|
-
workerOrchestrator.registerWorker(commandName);
|
|
192
|
+
yield workerOrchestrator.registerWorker(commandName);
|
|
149
193
|
const completedHandler = mockWorker.on.mock.calls.find((call) => call[0] === 'completed')[1];
|
|
150
194
|
const mockJob = {
|
|
151
195
|
id: 'job-123',
|
|
@@ -160,11 +204,11 @@ describe('WorkerOrchestrator', () => {
|
|
|
160
204
|
jobId: 'job-123',
|
|
161
205
|
hasReturnValue: true,
|
|
162
206
|
}));
|
|
163
|
-
});
|
|
164
|
-
it("powinno zalogować event 'active'", () => {
|
|
207
|
+
}));
|
|
208
|
+
it("powinno zalogować event 'active'", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
165
209
|
// Given
|
|
166
210
|
const commandName = 'TestCommand';
|
|
167
|
-
workerOrchestrator.registerWorker(commandName);
|
|
211
|
+
yield workerOrchestrator.registerWorker(commandName);
|
|
168
212
|
const activeHandler = mockWorker.on.mock.calls.find((call) => call[0] === 'active')[1];
|
|
169
213
|
const mockJob = {
|
|
170
214
|
id: 'job-123',
|
|
@@ -177,11 +221,11 @@ describe('WorkerOrchestrator', () => {
|
|
|
177
221
|
commandName,
|
|
178
222
|
jobId: 'job-123',
|
|
179
223
|
}));
|
|
180
|
-
});
|
|
181
|
-
it("powinno zalogować event 'stalled'", () => {
|
|
224
|
+
}));
|
|
225
|
+
it("powinno zalogować event 'stalled'", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
182
226
|
// Given
|
|
183
227
|
const commandName = 'TestCommand';
|
|
184
|
-
workerOrchestrator.registerWorker(commandName);
|
|
228
|
+
yield workerOrchestrator.registerWorker(commandName);
|
|
185
229
|
const stalledHandler = mockWorker.on.mock.calls.find((call) => call[0] === 'stalled')[1];
|
|
186
230
|
const jobId = 'job-123';
|
|
187
231
|
// When
|
|
@@ -192,11 +236,11 @@ describe('WorkerOrchestrator', () => {
|
|
|
192
236
|
jobId,
|
|
193
237
|
reason: 'Prawdopodobnie worker przestał odpowiadać',
|
|
194
238
|
}));
|
|
195
|
-
});
|
|
196
|
-
it("powinno zalogować event 'progress'", () => {
|
|
239
|
+
}));
|
|
240
|
+
it("powinno zalogować event 'progress'", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
197
241
|
// Given
|
|
198
242
|
const commandName = 'TestCommand';
|
|
199
|
-
workerOrchestrator.registerWorker(commandName);
|
|
243
|
+
yield workerOrchestrator.registerWorker(commandName);
|
|
200
244
|
const progressHandler = mockWorker.on.mock.calls.find((call) => call[0] === 'progress')[1];
|
|
201
245
|
const mockJob = {
|
|
202
246
|
id: 'job-123',
|
|
@@ -211,11 +255,11 @@ describe('WorkerOrchestrator', () => {
|
|
|
211
255
|
jobId: 'job-123',
|
|
212
256
|
progress: 50,
|
|
213
257
|
}));
|
|
214
|
-
});
|
|
215
|
-
it("powinno zalogować event 'error'", () => {
|
|
258
|
+
}));
|
|
259
|
+
it("powinno zalogować event 'error'", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
216
260
|
// Given
|
|
217
261
|
const commandName = 'TestCommand';
|
|
218
|
-
workerOrchestrator.registerWorker(commandName);
|
|
262
|
+
yield workerOrchestrator.registerWorker(commandName);
|
|
219
263
|
const errorHandler = mockWorker.on.mock.calls.find((call) => call[0] === 'error')[1];
|
|
220
264
|
const error = new Error('Worker error');
|
|
221
265
|
// When
|
|
@@ -225,11 +269,11 @@ describe('WorkerOrchestrator', () => {
|
|
|
225
269
|
commandName,
|
|
226
270
|
error: 'Worker error',
|
|
227
271
|
}));
|
|
228
|
-
});
|
|
229
|
-
it('powinno obsłużyć brak attempt info w failed event', () => {
|
|
272
|
+
}));
|
|
273
|
+
it('powinno obsłużyć brak attempt info w failed event', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
230
274
|
// Given
|
|
231
275
|
const commandName = 'TestCommand';
|
|
232
|
-
workerOrchestrator.registerWorker(commandName);
|
|
276
|
+
yield workerOrchestrator.registerWorker(commandName);
|
|
233
277
|
const failedHandler = mockWorker.on.mock.calls.find((call) => call[0] === 'failed')[1];
|
|
234
278
|
const mockJob = {
|
|
235
279
|
id: 'job-123',
|
|
@@ -245,18 +289,18 @@ describe('WorkerOrchestrator', () => {
|
|
|
245
289
|
maxAttempts,
|
|
246
290
|
isRetryable: true, // (0 || 0) < maxAttempts = true
|
|
247
291
|
}));
|
|
248
|
-
});
|
|
292
|
+
}));
|
|
249
293
|
});
|
|
250
294
|
describe('getWorker', () => {
|
|
251
|
-
it('powinno zwrócić workera dla komendy', () => {
|
|
295
|
+
it('powinno zwrócić workera dla komendy', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
252
296
|
// Given
|
|
253
297
|
const commandName = 'TestCommand';
|
|
254
|
-
workerOrchestrator.registerWorker(commandName);
|
|
298
|
+
yield workerOrchestrator.registerWorker(commandName);
|
|
255
299
|
// When
|
|
256
300
|
const worker = workerOrchestrator.getWorker(commandName);
|
|
257
301
|
// Then
|
|
258
302
|
expect(worker).toBe(mockWorker);
|
|
259
|
-
});
|
|
303
|
+
}));
|
|
260
304
|
it('powinno zwrócić undefined dla niezarejestrowanego workera', () => {
|
|
261
305
|
// When
|
|
262
306
|
const worker = workerOrchestrator.getWorker('NonExistentCommand');
|
|
@@ -267,17 +311,22 @@ describe('WorkerOrchestrator', () => {
|
|
|
267
311
|
describe('closeAll', () => {
|
|
268
312
|
it('powinno zamknąć wszystkich workerów', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
269
313
|
// Given
|
|
270
|
-
workerOrchestrator.registerWorker('TestCommand1');
|
|
271
|
-
workerOrchestrator.registerWorker('TestCommand2');
|
|
272
|
-
workerOrchestrator.registerWorker('TestCommand3');
|
|
314
|
+
yield workerOrchestrator.registerWorker('TestCommand1');
|
|
315
|
+
yield workerOrchestrator.registerWorker('TestCommand2');
|
|
316
|
+
yield workerOrchestrator.registerWorker('TestCommand3');
|
|
317
|
+
const worker1 = workerOrchestrator.getWorker('TestCommand1');
|
|
318
|
+
const worker2 = workerOrchestrator.getWorker('TestCommand2');
|
|
319
|
+
const worker3 = workerOrchestrator.getWorker('TestCommand3');
|
|
273
320
|
// When
|
|
274
321
|
yield workerOrchestrator.closeAll();
|
|
275
|
-
// Then
|
|
276
|
-
expect(
|
|
322
|
+
// Then - każdy worker powinien mieć wywołane close
|
|
323
|
+
expect(worker1 === null || worker1 === void 0 ? void 0 : worker1.close).toHaveBeenCalledTimes(1);
|
|
324
|
+
expect(worker2 === null || worker2 === void 0 ? void 0 : worker2.close).toHaveBeenCalledTimes(1);
|
|
325
|
+
expect(worker3 === null || worker3 === void 0 ? void 0 : worker3.close).toHaveBeenCalledTimes(1);
|
|
277
326
|
}));
|
|
278
327
|
it('powinno wyczyścić cache workerów', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
279
328
|
// Given
|
|
280
|
-
workerOrchestrator.registerWorker('TestCommand');
|
|
329
|
+
yield workerOrchestrator.registerWorker('TestCommand');
|
|
281
330
|
yield workerOrchestrator.closeAll();
|
|
282
331
|
// When
|
|
283
332
|
const worker = workerOrchestrator.getWorker('TestCommand');
|
|
@@ -288,6 +337,378 @@ describe('WorkerOrchestrator', () => {
|
|
|
288
337
|
// When & Then
|
|
289
338
|
yield expect(workerOrchestrator.closeAll()).resolves.toBeUndefined();
|
|
290
339
|
}));
|
|
340
|
+
it('powinno zatrzymać wszystkie collectory metryk', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
341
|
+
// Given
|
|
342
|
+
const WorkerMetricsCollector = jest.requireMock('./worker-metrics-collector');
|
|
343
|
+
yield workerOrchestrator.registerWorker('TestCommand');
|
|
344
|
+
// When
|
|
345
|
+
yield workerOrchestrator.closeAll();
|
|
346
|
+
// Then
|
|
347
|
+
const collectorInstance = WorkerMetricsCollector.mock.results[0].value;
|
|
348
|
+
expect(collectorInstance.stop).toHaveBeenCalled();
|
|
349
|
+
}));
|
|
350
|
+
it('powinno usunąć wszystkie event listeners przed zamknięciem', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
351
|
+
// Given
|
|
352
|
+
yield workerOrchestrator.registerWorker('TestCommand');
|
|
353
|
+
// When
|
|
354
|
+
yield workerOrchestrator.closeAll();
|
|
355
|
+
// Then
|
|
356
|
+
expect(mockWorker.removeAllListeners).toHaveBeenCalled();
|
|
357
|
+
}));
|
|
358
|
+
});
|
|
359
|
+
describe('adjustConcurrency', () => {
|
|
360
|
+
beforeEach(() => {
|
|
361
|
+
jest.useFakeTimers();
|
|
362
|
+
});
|
|
363
|
+
afterEach(() => {
|
|
364
|
+
jest.useRealTimers();
|
|
365
|
+
});
|
|
366
|
+
it('powinno zwiększyć concurrency o 20%', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
367
|
+
// Given - użyj wyższego początkowego concurrency żeby test był sensowny
|
|
368
|
+
const WorkerBenchmark = jest.requireMock('./worker-benchmark');
|
|
369
|
+
WorkerBenchmark.mockImplementation(() => ({
|
|
370
|
+
run: jest.fn().mockResolvedValue({
|
|
371
|
+
recommendedConcurrency: 50, // Wysokie początkowe concurrency
|
|
372
|
+
jobsPerSecond: 100,
|
|
373
|
+
avgProcessingTime: 10,
|
|
374
|
+
}),
|
|
375
|
+
}));
|
|
376
|
+
const commandName = 'TestCommand';
|
|
377
|
+
yield workerOrchestrator.registerWorker(commandName);
|
|
378
|
+
const worker = workerOrchestrator.getWorker(commandName);
|
|
379
|
+
// When
|
|
380
|
+
workerOrchestrator.adjustConcurrency(commandName, 'increase', 'Test reason');
|
|
381
|
+
// Then: 50 * 1.2 = 60
|
|
382
|
+
expect(worker === null || worker === void 0 ? void 0 : worker.concurrency).toBe(60);
|
|
383
|
+
expect(mockLogger.log).toHaveBeenCalledWith('Dynamiczna zmiana concurrency', expect.objectContaining({
|
|
384
|
+
commandName,
|
|
385
|
+
oldConcurrency: 50,
|
|
386
|
+
newConcurrency: 60,
|
|
387
|
+
change: '+20%',
|
|
388
|
+
direction: 'increase',
|
|
389
|
+
reason: 'Test reason',
|
|
390
|
+
}));
|
|
391
|
+
}));
|
|
392
|
+
it('powinno zmniejszyć concurrency o 20%', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
393
|
+
// Given - użyj wyższego początkowego concurrency
|
|
394
|
+
const WorkerBenchmark = jest.requireMock('./worker-benchmark');
|
|
395
|
+
WorkerBenchmark.mockImplementation(() => ({
|
|
396
|
+
run: jest.fn().mockResolvedValue({
|
|
397
|
+
recommendedConcurrency: 50,
|
|
398
|
+
jobsPerSecond: 100,
|
|
399
|
+
avgProcessingTime: 10,
|
|
400
|
+
}),
|
|
401
|
+
}));
|
|
402
|
+
const commandName = 'TestCommand';
|
|
403
|
+
yield workerOrchestrator.registerWorker(commandName);
|
|
404
|
+
const worker = workerOrchestrator.getWorker(commandName);
|
|
405
|
+
// When
|
|
406
|
+
workerOrchestrator.adjustConcurrency(commandName, 'decrease', 'Low backlog');
|
|
407
|
+
// Then: 50 * 0.8 = 40
|
|
408
|
+
expect(worker === null || worker === void 0 ? void 0 : worker.concurrency).toBe(40);
|
|
409
|
+
expect(mockLogger.log).toHaveBeenCalledWith('Dynamiczna zmiana concurrency', expect.objectContaining({
|
|
410
|
+
oldConcurrency: 50,
|
|
411
|
+
newConcurrency: 40,
|
|
412
|
+
change: '-20%',
|
|
413
|
+
direction: 'decrease',
|
|
414
|
+
}));
|
|
415
|
+
}));
|
|
416
|
+
it('powinno zastosować limit minimum 10', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
417
|
+
// Given
|
|
418
|
+
const commandName = 'TestCommand';
|
|
419
|
+
yield workerOrchestrator.registerWorker(commandName);
|
|
420
|
+
const worker = workerOrchestrator.getWorker(commandName);
|
|
421
|
+
// Zmniejsz kilka razy do limitu
|
|
422
|
+
workerOrchestrator.adjustConcurrency(commandName, 'decrease', 'reason');
|
|
423
|
+
jest.advanceTimersByTime(31000); // Przekrocz cooldown
|
|
424
|
+
workerOrchestrator.adjustConcurrency(commandName, 'decrease', 'reason');
|
|
425
|
+
jest.advanceTimersByTime(31000);
|
|
426
|
+
workerOrchestrator.adjustConcurrency(commandName, 'decrease', 'reason');
|
|
427
|
+
jest.advanceTimersByTime(31000);
|
|
428
|
+
// When - próba zmniejszenia poniżej 10
|
|
429
|
+
workerOrchestrator.adjustConcurrency(commandName, 'decrease', 'reason');
|
|
430
|
+
// Then - powinno zatrzymać się na 10
|
|
431
|
+
expect(worker === null || worker === void 0 ? void 0 : worker.concurrency).toBeGreaterThanOrEqual(10);
|
|
432
|
+
}));
|
|
433
|
+
it('powinno zastosować limit maksimum 2000', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
434
|
+
// Given - mockuj benchmark aby zwrócił wysokie concurrency
|
|
435
|
+
const WorkerBenchmark = jest.requireMock('./worker-benchmark');
|
|
436
|
+
WorkerBenchmark.mockImplementation(() => ({
|
|
437
|
+
run: jest.fn().mockResolvedValue({
|
|
438
|
+
recommendedConcurrency: 1800,
|
|
439
|
+
jobsPerSecond: 1000,
|
|
440
|
+
avgProcessingTime: 5,
|
|
441
|
+
}),
|
|
442
|
+
}));
|
|
443
|
+
const commandName = 'HighConcurrencyCommand';
|
|
444
|
+
yield workerOrchestrator.registerWorker(commandName);
|
|
445
|
+
const worker = workerOrchestrator.getWorker(commandName);
|
|
446
|
+
// Zwiększ kilka razy
|
|
447
|
+
workerOrchestrator.adjustConcurrency(commandName, 'increase', 'reason');
|
|
448
|
+
jest.advanceTimersByTime(31000);
|
|
449
|
+
workerOrchestrator.adjustConcurrency(commandName, 'increase', 'reason');
|
|
450
|
+
jest.advanceTimersByTime(31000);
|
|
451
|
+
// When - próba zwiększenia powyżej 2000
|
|
452
|
+
workerOrchestrator.adjustConcurrency(commandName, 'increase', 'reason');
|
|
453
|
+
// Then - powinno zatrzymać się na 2000
|
|
454
|
+
expect(worker === null || worker === void 0 ? void 0 : worker.concurrency).toBeLessThanOrEqual(2000);
|
|
455
|
+
}));
|
|
456
|
+
it('powinno respektować cooldown 30s między zmianami', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
457
|
+
// Given
|
|
458
|
+
const commandName = 'TestCommand';
|
|
459
|
+
yield workerOrchestrator.registerWorker(commandName);
|
|
460
|
+
const worker = workerOrchestrator.getWorker(commandName);
|
|
461
|
+
// First change
|
|
462
|
+
workerOrchestrator.adjustConcurrency(commandName, 'increase', 'reason 1');
|
|
463
|
+
const firstConcurrency = worker === null || worker === void 0 ? void 0 : worker.concurrency;
|
|
464
|
+
// When - próba zmiany w czasie cooldown
|
|
465
|
+
jest.advanceTimersByTime(15000); // 15s - poniżej cooldown
|
|
466
|
+
workerOrchestrator.adjustConcurrency(commandName, 'increase', 'reason 2');
|
|
467
|
+
// Then - concurrency nie powinno się zmienić
|
|
468
|
+
expect(worker === null || worker === void 0 ? void 0 : worker.concurrency).toBe(firstConcurrency);
|
|
469
|
+
expect(mockLogger.debug).toHaveBeenCalledWith('Cooldown aktywny - pomijam zmianę concurrency', expect.any(Object));
|
|
470
|
+
}));
|
|
471
|
+
it('powinno pozwolić na zmianę po upływie cooldown', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
472
|
+
var _a;
|
|
473
|
+
// Given - użyj wyższego początkowego concurrency
|
|
474
|
+
const WorkerBenchmark = jest.requireMock('./worker-benchmark');
|
|
475
|
+
WorkerBenchmark.mockImplementation(() => ({
|
|
476
|
+
run: jest.fn().mockResolvedValue({
|
|
477
|
+
recommendedConcurrency: 1000,
|
|
478
|
+
jobsPerSecond: 100,
|
|
479
|
+
avgProcessingTime: 10,
|
|
480
|
+
}),
|
|
481
|
+
}));
|
|
482
|
+
const commandName = 'TestCommand';
|
|
483
|
+
yield workerOrchestrator.registerWorker(commandName);
|
|
484
|
+
const worker = workerOrchestrator.getWorker(commandName);
|
|
485
|
+
// First change: 1000 * 1.2 = 1200
|
|
486
|
+
workerOrchestrator.adjustConcurrency(commandName, 'increase', 'reason 1');
|
|
487
|
+
const firstConcurrency = (_a = worker === null || worker === void 0 ? void 0 : worker.concurrency) !== null && _a !== void 0 ? _a : 0;
|
|
488
|
+
expect(firstConcurrency).toBe(1200);
|
|
489
|
+
// When - czekamy > 30s i zmieniamy ponownie
|
|
490
|
+
jest.advanceTimersByTime(31000); // 31s - powyżej cooldown
|
|
491
|
+
workerOrchestrator.adjustConcurrency(commandName, 'increase', 'reason 2');
|
|
492
|
+
// Then - concurrency powinno się zmienić: 1200 * 1.2 = 1440
|
|
493
|
+
expect(worker === null || worker === void 0 ? void 0 : worker.concurrency).toBe(1440);
|
|
494
|
+
}));
|
|
495
|
+
it('powinno zalogować warning gdy worker nie istnieje', () => {
|
|
496
|
+
// When
|
|
497
|
+
workerOrchestrator.adjustConcurrency('NonExistentCommand', 'increase', 'reason');
|
|
498
|
+
// Then
|
|
499
|
+
expect(mockLogger.warn).toHaveBeenCalledWith('Nie można dostosować concurrency - worker nie istnieje', expect.objectContaining({
|
|
500
|
+
commandName: 'NonExistentCommand',
|
|
501
|
+
}));
|
|
502
|
+
});
|
|
503
|
+
it('nie powinno zmieniać concurrency gdy wartość się nie zmienia (na limicie)', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
504
|
+
var _a;
|
|
505
|
+
// Given - zresetuj mock benchmark do domyślnych wartości
|
|
506
|
+
const WorkerBenchmark = jest.requireMock('./worker-benchmark');
|
|
507
|
+
WorkerBenchmark.mockImplementation(() => ({
|
|
508
|
+
run: jest.fn().mockResolvedValue({
|
|
509
|
+
recommendedConcurrency: 50, // Wystarczająco wysokie aby test miał sens
|
|
510
|
+
jobsPerSecond: 100,
|
|
511
|
+
avgProcessingTime: 10,
|
|
512
|
+
}),
|
|
513
|
+
}));
|
|
514
|
+
const commandName = 'TestCommand';
|
|
515
|
+
yield workerOrchestrator.registerWorker(commandName);
|
|
516
|
+
const worker = workerOrchestrator.getWorker(commandName);
|
|
517
|
+
// Ustaw na minimum (10): 50 -> 40 -> 32 -> 26 -> 21 -> 17 -> 14 -> 11 -> 10 -> 10
|
|
518
|
+
for (let i = 0; i < 10; i++) {
|
|
519
|
+
workerOrchestrator.adjustConcurrency(commandName, 'decrease', 'reason');
|
|
520
|
+
jest.advanceTimersByTime(31000);
|
|
521
|
+
}
|
|
522
|
+
const minConcurrency = (_a = worker === null || worker === void 0 ? void 0 : worker.concurrency) !== null && _a !== void 0 ? _a : 0;
|
|
523
|
+
expect(minConcurrency).toBe(10); // Powinno osiągnąć minimum 10
|
|
524
|
+
// When - próba dalszego zmniejszenia na limicie
|
|
525
|
+
workerOrchestrator.adjustConcurrency(commandName, 'decrease', 'reason');
|
|
526
|
+
// Then - wartość nie powinna się zmienić
|
|
527
|
+
expect(worker === null || worker === void 0 ? void 0 : worker.concurrency).toBe(minConcurrency);
|
|
528
|
+
expect(mockLogger.debug).toHaveBeenCalledWith('Concurrency bez zmian - osiągnięto limit', expect.any(Object));
|
|
529
|
+
}));
|
|
530
|
+
});
|
|
531
|
+
describe('integracja z WorkerBenchmark', () => {
|
|
532
|
+
it('powinno uruchomić benchmark przed utworzeniem workera', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
533
|
+
// Given
|
|
534
|
+
const WorkerBenchmark = jest.requireMock('./worker-benchmark');
|
|
535
|
+
const commandName = 'TestCommand';
|
|
536
|
+
// When
|
|
537
|
+
yield workerOrchestrator.registerWorker(commandName);
|
|
538
|
+
// Then
|
|
539
|
+
expect(WorkerBenchmark).toHaveBeenCalledWith(commandName, mockRedisConnection, mockJobProcessor, mockLogger);
|
|
540
|
+
const benchmarkInstance = WorkerBenchmark.mock.results[0].value;
|
|
541
|
+
expect(benchmarkInstance.run).toHaveBeenCalled();
|
|
542
|
+
}));
|
|
543
|
+
it('powinno użyć recommendedConcurrency z benchmarku', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
544
|
+
// Given
|
|
545
|
+
const WorkerBenchmark = jest.requireMock('./worker-benchmark');
|
|
546
|
+
WorkerBenchmark.mockImplementation(() => ({
|
|
547
|
+
run: jest.fn().mockResolvedValue({
|
|
548
|
+
recommendedConcurrency: 42,
|
|
549
|
+
jobsPerSecond: 200,
|
|
550
|
+
avgProcessingTime: 20,
|
|
551
|
+
}),
|
|
552
|
+
}));
|
|
553
|
+
const commandName = 'OptimizedCommand';
|
|
554
|
+
// When
|
|
555
|
+
yield workerOrchestrator.registerWorker(commandName);
|
|
556
|
+
// Then
|
|
557
|
+
expect(bullmq_1.Worker).toHaveBeenCalledWith(`{${commandName}}`, expect.any(Function), expect.objectContaining({
|
|
558
|
+
concurrency: 42,
|
|
559
|
+
}));
|
|
560
|
+
}));
|
|
561
|
+
});
|
|
562
|
+
describe('integracja z WorkerMetricsCollector', () => {
|
|
563
|
+
it('powinno utworzyć i uruchomić metrics collector', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
564
|
+
// Given
|
|
565
|
+
const WorkerMetricsCollector = jest.requireMock('./worker-metrics-collector');
|
|
566
|
+
const commandName = 'TestCommand';
|
|
567
|
+
// When
|
|
568
|
+
yield workerOrchestrator.registerWorker(commandName);
|
|
569
|
+
// Then
|
|
570
|
+
expect(WorkerMetricsCollector).toHaveBeenCalledWith(commandName, expect.any(Object), // queue
|
|
571
|
+
mockLogger, expect.any(Function));
|
|
572
|
+
const collectorInstance = WorkerMetricsCollector.mock.results[0].value;
|
|
573
|
+
expect(collectorInstance.start).toHaveBeenCalled();
|
|
574
|
+
}));
|
|
575
|
+
it('powinno wywołać adjustConcurrency gdy collector rekomenduje zmianę', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
576
|
+
// Given
|
|
577
|
+
const commandName = 'TestCommand';
|
|
578
|
+
yield workerOrchestrator.registerWorker(commandName);
|
|
579
|
+
// Pobierz callback przekazany do WorkerMetricsCollector
|
|
580
|
+
const WorkerMetricsCollector = jest.requireMock('./worker-metrics-collector');
|
|
581
|
+
const collectorCallback = WorkerMetricsCollector.mock.calls[0][3];
|
|
582
|
+
// When - symuluj rekomendację od collectora
|
|
583
|
+
collectorCallback({
|
|
584
|
+
shouldAdjust: true,
|
|
585
|
+
direction: 'increase',
|
|
586
|
+
reason: 'High backlog detected',
|
|
587
|
+
currentMetrics: {
|
|
588
|
+
waiting: 100,
|
|
589
|
+
active: 10,
|
|
590
|
+
jobsPerSecond: 5,
|
|
591
|
+
avgProcessingTimeMs: 200,
|
|
592
|
+
timestamp: Date.now(),
|
|
593
|
+
},
|
|
594
|
+
});
|
|
595
|
+
// Then
|
|
596
|
+
expect(mockWorker.concurrency).toBeGreaterThan(5); // Zwiększone o 20%
|
|
597
|
+
}));
|
|
598
|
+
it('nie powinno wywoływać adjustConcurrency gdy direction=none', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
599
|
+
// Given
|
|
600
|
+
const commandName = 'TestCommand';
|
|
601
|
+
yield workerOrchestrator.registerWorker(commandName);
|
|
602
|
+
const WorkerMetricsCollector = jest.requireMock('./worker-metrics-collector');
|
|
603
|
+
const collectorCallback = WorkerMetricsCollector.mock.calls[0][3];
|
|
604
|
+
const initialConcurrency = mockWorker.concurrency;
|
|
605
|
+
// When - symuluj brak rekomendacji
|
|
606
|
+
collectorCallback({
|
|
607
|
+
shouldAdjust: false,
|
|
608
|
+
direction: 'none',
|
|
609
|
+
reason: 'Stable metrics',
|
|
610
|
+
currentMetrics: {
|
|
611
|
+
waiting: 10,
|
|
612
|
+
active: 10,
|
|
613
|
+
jobsPerSecond: 10,
|
|
614
|
+
avgProcessingTimeMs: 100,
|
|
615
|
+
timestamp: Date.now(),
|
|
616
|
+
},
|
|
617
|
+
});
|
|
618
|
+
// Then - concurrency nie zmienione
|
|
619
|
+
expect(mockWorker.concurrency).toBe(initialConcurrency);
|
|
620
|
+
}));
|
|
621
|
+
});
|
|
622
|
+
describe('tracking czasu przetwarzania jobów', () => {
|
|
623
|
+
beforeEach(() => {
|
|
624
|
+
jest.useFakeTimers();
|
|
625
|
+
});
|
|
626
|
+
afterEach(() => {
|
|
627
|
+
jest.useRealTimers();
|
|
628
|
+
});
|
|
629
|
+
it('powinno zapisać czas przetwarzania w metricsCollector', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
630
|
+
// Given
|
|
631
|
+
const commandName = 'TestCommand';
|
|
632
|
+
yield workerOrchestrator.registerWorker(commandName);
|
|
633
|
+
const WorkerMetricsCollector = jest.requireMock('./worker-metrics-collector');
|
|
634
|
+
const collectorInstance = WorkerMetricsCollector.mock.results[0].value;
|
|
635
|
+
// Pobierz handlery eventów
|
|
636
|
+
const activeHandler = mockWorker.on.mock.calls.find((call) => call[0] === 'active')[1];
|
|
637
|
+
const completedHandler = mockWorker.on.mock.calls.find((call) => call[0] === 'completed')[1];
|
|
638
|
+
const mockJob = {
|
|
639
|
+
id: 'job-123',
|
|
640
|
+
data: { __id: 'cmd-123' },
|
|
641
|
+
returnvalue: { success: true },
|
|
642
|
+
};
|
|
643
|
+
// When - symuluj job lifecycle
|
|
644
|
+
activeHandler(mockJob); // Start job
|
|
645
|
+
jest.advanceTimersByTime(150); // 150ms przetwarzania
|
|
646
|
+
completedHandler(mockJob); // Complete job
|
|
647
|
+
// Then - czas przetwarzania powinien być zapisany
|
|
648
|
+
expect(collectorInstance.recordJobProcessingTime).toHaveBeenCalledWith(150);
|
|
649
|
+
}));
|
|
650
|
+
it('powinno obsłużyć sytuację gdy brak jobId', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
651
|
+
// Given
|
|
652
|
+
const commandName = 'TestCommand';
|
|
653
|
+
yield workerOrchestrator.registerWorker(commandName);
|
|
654
|
+
const completedHandler = mockWorker.on.mock.calls.find((call) => call[0] === 'completed')[1];
|
|
655
|
+
const mockJob = {
|
|
656
|
+
id: undefined, // Brak ID
|
|
657
|
+
data: { __id: 'cmd-123' },
|
|
658
|
+
};
|
|
659
|
+
// When
|
|
660
|
+
completedHandler(mockJob);
|
|
661
|
+
// Then - nie powinno wywołać recordJobProcessingTime
|
|
662
|
+
const WorkerMetricsCollector = jest.requireMock('./worker-metrics-collector');
|
|
663
|
+
const collectorInstance = WorkerMetricsCollector.mock.results[0].value;
|
|
664
|
+
expect(collectorInstance.recordJobProcessingTime).not.toHaveBeenCalled();
|
|
665
|
+
}));
|
|
666
|
+
it('powinno wyczyścić czas startu dla failed jobs', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
667
|
+
// Given
|
|
668
|
+
const commandName = 'TestCommand';
|
|
669
|
+
yield workerOrchestrator.registerWorker(commandName);
|
|
670
|
+
const activeHandler = mockWorker.on.mock.calls.find((call) => call[0] === 'active')[1];
|
|
671
|
+
const failedHandler = mockWorker.on.mock.calls.find((call) => call[0] === 'failed')[1];
|
|
672
|
+
const completedHandler = mockWorker.on.mock.calls.find((call) => call[0] === 'completed')[1];
|
|
673
|
+
const mockJob = {
|
|
674
|
+
id: 'job-123',
|
|
675
|
+
data: { __id: 'cmd-123' },
|
|
676
|
+
attemptsMade: 1,
|
|
677
|
+
opts: { attempts: 3 },
|
|
678
|
+
};
|
|
679
|
+
// When - job fails
|
|
680
|
+
activeHandler(mockJob);
|
|
681
|
+
failedHandler(mockJob, new Error('Job failed'));
|
|
682
|
+
// Then - próba completed nie powinna zapisać czasu (start time został wyczyszczony)
|
|
683
|
+
completedHandler(mockJob);
|
|
684
|
+
const WorkerMetricsCollector = jest.requireMock('./worker-metrics-collector');
|
|
685
|
+
const collectorInstance = WorkerMetricsCollector.mock.results[0].value;
|
|
686
|
+
// recordJobProcessingTime nie powinno być wywołane dla failed job
|
|
687
|
+
expect(collectorInstance.recordJobProcessingTime).not.toHaveBeenCalled();
|
|
688
|
+
}));
|
|
689
|
+
});
|
|
690
|
+
describe('getWorkerStats', () => {
|
|
691
|
+
it('powinno zwrócić statystyki workerów', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
692
|
+
// Given
|
|
693
|
+
yield workerOrchestrator.registerWorker('Command1');
|
|
694
|
+
yield workerOrchestrator.registerWorker('Command2');
|
|
695
|
+
// When
|
|
696
|
+
const stats = workerOrchestrator.getWorkerStats();
|
|
697
|
+
// Then
|
|
698
|
+
expect(stats).toEqual({
|
|
699
|
+
activeWorkersCount: 2,
|
|
700
|
+
workerNames: ['Command1', 'Command2'],
|
|
701
|
+
});
|
|
702
|
+
}));
|
|
703
|
+
it('powinno zwrócić puste statystyki gdy brak workerów', () => {
|
|
704
|
+
// When
|
|
705
|
+
const stats = workerOrchestrator.getWorkerStats();
|
|
706
|
+
// Then
|
|
707
|
+
expect(stats).toEqual({
|
|
708
|
+
activeWorkersCount: 0,
|
|
709
|
+
workerNames: [],
|
|
710
|
+
});
|
|
711
|
+
});
|
|
291
712
|
});
|
|
292
713
|
});
|
|
293
714
|
//# sourceMappingURL=worker-orchestrator.spec.js.map
|