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