pp-command-bus 1.0.3 → 1.2.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 +41 -9
- 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 +2 -2
- package/dist/command-bus/index.js +26 -15
- package/dist/command-bus/index.js.map +1 -1
- package/dist/command-bus/job/job-processor.d.ts +8 -10
- package/dist/command-bus/job/job-processor.js +23 -113
- package/dist/command-bus/job/job-processor.js.map +1 -1
- package/dist/command-bus/job/job-processor.spec.js +17 -107
- package/dist/command-bus/job/job-processor.spec.js.map +1 -1
- package/dist/command-bus/rpc/rpc-coordinator.d.ts +39 -16
- package/dist/command-bus/rpc/rpc-coordinator.js +178 -93
- package/dist/command-bus/rpc/rpc-coordinator.js.map +1 -1
- package/dist/command-bus/rpc/rpc-coordinator.spec.js +64 -223
- package/dist/command-bus/rpc/rpc-coordinator.spec.js.map +1 -1
- package/dist/command-bus/types/index.d.ts +5 -4
- 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 +71 -0
- package/dist/command-bus/worker/worker-benchmark.js +203 -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 +310 -0
- package/dist/command-bus/worker/worker-benchmark.spec.js.map +1 -0
- package/dist/command-bus/worker/worker-metrics-collector.d.ts +98 -0
- package/dist/command-bus/worker/worker-metrics-collector.js +242 -0
- package/dist/command-bus/worker/worker-metrics-collector.js.map +1 -0
- package/dist/command-bus/worker/worker-orchestrator.d.ts +29 -4
- package/dist/command-bus/worker/worker-orchestrator.js +193 -27
- package/dist/command-bus/worker/worker-orchestrator.js.map +1 -1
- package/dist/command-bus/worker/worker-orchestrator.spec.js +477 -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.2.0.tgz +0 -0
- package/package.json +3 -2
- package/dist/pp-command-bus-1.0.3.tgz +0 -0
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
/**
|
|
4
|
+
* Zbiera metryki workera w trybie event-driven
|
|
5
|
+
* Resetuje dane co 1 minutę (okno profilowania)
|
|
6
|
+
* Nie używa setInterval - bazuje na eventach jobów
|
|
7
|
+
*/
|
|
8
|
+
class WorkerMetricsCollector {
|
|
9
|
+
constructor(commandName, logger, onConcurrencyRecommendation) {
|
|
10
|
+
this.commandName = commandName;
|
|
11
|
+
this.logger = logger;
|
|
12
|
+
this.onConcurrencyRecommendation = onConcurrencyRecommendation;
|
|
13
|
+
/**
|
|
14
|
+
* Długość okna profilowania w ms (1 minuta)
|
|
15
|
+
*/
|
|
16
|
+
this.PROFILING_WINDOW_MS = 60000;
|
|
17
|
+
/**
|
|
18
|
+
* Timestamp rozpoczęcia aktualnego okna profilowania
|
|
19
|
+
*/
|
|
20
|
+
this.profilingWindowStartTime = 0;
|
|
21
|
+
/**
|
|
22
|
+
* Licznik ukończonych jobów w aktualnym oknie
|
|
23
|
+
*/
|
|
24
|
+
this.completedCount = 0;
|
|
25
|
+
/**
|
|
26
|
+
* Licznik nieudanych jobów w aktualnym oknie
|
|
27
|
+
*/
|
|
28
|
+
this.failedCount = 0;
|
|
29
|
+
/**
|
|
30
|
+
* Licznik aktywnie przetwarzanych jobów (lokalny counter)
|
|
31
|
+
*/
|
|
32
|
+
this.activeCount = 0;
|
|
33
|
+
/**
|
|
34
|
+
* Czasy przetwarzania jobów w aktualnym oknie (ms)
|
|
35
|
+
*/
|
|
36
|
+
this.processingTimes = [];
|
|
37
|
+
/**
|
|
38
|
+
* Historia średnich wartości activeCount dla analizy trendów
|
|
39
|
+
* Zbierana przy każdym evencie completed/failed
|
|
40
|
+
*/
|
|
41
|
+
this.activeCountHistory = [];
|
|
42
|
+
this.maxActiveCountHistory = 30;
|
|
43
|
+
// Zainicjuj okno profilowania
|
|
44
|
+
this.profilingWindowStartTime = Date.now();
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Wywołane gdy job zostaje aktywowany (rozpoczęty)
|
|
48
|
+
* @param jobId - ID joba
|
|
49
|
+
*/
|
|
50
|
+
onJobActive(jobId) {
|
|
51
|
+
this.activeCount++;
|
|
52
|
+
this.logger.debug('Job aktywowany - metryki', {
|
|
53
|
+
commandName: this.commandName,
|
|
54
|
+
jobId,
|
|
55
|
+
activeCount: this.activeCount,
|
|
56
|
+
timestamp: new Date().toISOString(),
|
|
57
|
+
});
|
|
58
|
+
// Sprawdź czy minęło okno profilowania
|
|
59
|
+
this.checkWindowReset();
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Wywołane gdy job zostaje ukończony pomyślnie
|
|
63
|
+
* @param jobId - ID joba
|
|
64
|
+
* @param processingTimeMs - Czas przetwarzania w ms
|
|
65
|
+
*/
|
|
66
|
+
onJobCompleted(jobId, processingTimeMs) {
|
|
67
|
+
this.activeCount--;
|
|
68
|
+
this.completedCount++;
|
|
69
|
+
this.processingTimes.push(processingTimeMs);
|
|
70
|
+
// Zapisz snapshot activeCount dla analizy trendów
|
|
71
|
+
this.recordActiveCountSnapshot();
|
|
72
|
+
this.logger.debug('Job ukończony - metryki', {
|
|
73
|
+
commandName: this.commandName,
|
|
74
|
+
jobId,
|
|
75
|
+
processingTimeMs,
|
|
76
|
+
activeCount: this.activeCount,
|
|
77
|
+
completedCount: this.completedCount,
|
|
78
|
+
timestamp: new Date().toISOString(),
|
|
79
|
+
});
|
|
80
|
+
// Sprawdź czy minęło okno profilowania
|
|
81
|
+
this.checkWindowReset();
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Wywołane gdy job kończy się niepowodzeniem
|
|
85
|
+
* @param jobId - ID joba
|
|
86
|
+
*/
|
|
87
|
+
onJobFailed(jobId) {
|
|
88
|
+
this.activeCount--;
|
|
89
|
+
this.failedCount++;
|
|
90
|
+
// Zapisz snapshot activeCount dla analizy trendów
|
|
91
|
+
this.recordActiveCountSnapshot();
|
|
92
|
+
this.logger.debug('Job nieudany - metryki', {
|
|
93
|
+
commandName: this.commandName,
|
|
94
|
+
jobId,
|
|
95
|
+
activeCount: this.activeCount,
|
|
96
|
+
failedCount: this.failedCount,
|
|
97
|
+
timestamp: new Date().toISOString(),
|
|
98
|
+
});
|
|
99
|
+
// Sprawdź czy minęło okno profilowania
|
|
100
|
+
this.checkWindowReset();
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Sprawdza czy minęło okno profilowania (1 minuta)
|
|
104
|
+
* Jeśli tak, loguje podsumowanie, analizuje i resetuje
|
|
105
|
+
*/
|
|
106
|
+
checkWindowReset() {
|
|
107
|
+
const windowElapsedMs = Date.now() - this.profilingWindowStartTime;
|
|
108
|
+
if (windowElapsedMs >= this.PROFILING_WINDOW_MS) {
|
|
109
|
+
this.displayMetricsAndReset();
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Wyświetla podsumowanie okna, analizuje metryki i resetuje liczniki
|
|
114
|
+
*/
|
|
115
|
+
displayMetricsAndReset() {
|
|
116
|
+
const windowStats = this.calculateWindowStats();
|
|
117
|
+
this.logger.log(`Podsumowanie okna profilowania ${this.commandName}`, windowStats);
|
|
118
|
+
// Jeśli mamy wystarczająco danych (przynajmniej 5 jobów), wygeneruj rekomendację
|
|
119
|
+
if (this.completedCount >= 5 && this.activeCountHistory.length >= 5) {
|
|
120
|
+
const recommendation = this.analyzeAndRecommendConcurrency();
|
|
121
|
+
this.logger.log(`Rekomendacja concurrency (koniec okna) ${this.commandName}`, recommendation);
|
|
122
|
+
if (recommendation.shouldAdjust && this.onConcurrencyRecommendation) {
|
|
123
|
+
this.onConcurrencyRecommendation(recommendation);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
else {
|
|
127
|
+
this.logger.debug('Za mało danych dla rekomendacji concurrency', {
|
|
128
|
+
commandName: this.commandName,
|
|
129
|
+
completedCount: this.completedCount,
|
|
130
|
+
activeCountHistorySize: this.activeCountHistory.length,
|
|
131
|
+
timestamp: new Date().toISOString(),
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
// Reset okna profilowania
|
|
135
|
+
this.resetProfilingWindow();
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Oblicza statystyki dla aktualnego okna profilowania
|
|
139
|
+
*/
|
|
140
|
+
calculateWindowStats() {
|
|
141
|
+
const windowDurationMs = Date.now() - this.profilingWindowStartTime;
|
|
142
|
+
const windowDurationSec = windowDurationMs / 1000;
|
|
143
|
+
// Oblicz średni czas przetwarzania
|
|
144
|
+
const avgProcessingTimeMs = this.processingTimes.length > 0
|
|
145
|
+
? this.processingTimes.reduce((sum, time) => sum + time, 0) / this.processingTimes.length
|
|
146
|
+
: 0;
|
|
147
|
+
// Oblicz przepustowość
|
|
148
|
+
const jobsPerSecond = windowDurationSec > 0 ? this.completedCount / windowDurationSec : 0;
|
|
149
|
+
const jobsPerMinute = jobsPerSecond * 60;
|
|
150
|
+
return {
|
|
151
|
+
commandName: this.commandName,
|
|
152
|
+
windowDurationMs: Math.round(windowDurationMs),
|
|
153
|
+
completedJobs: this.completedCount,
|
|
154
|
+
failedJobs: this.failedCount,
|
|
155
|
+
currentActiveJobs: this.activeCount,
|
|
156
|
+
avgProcessingTimeMs: Math.round(avgProcessingTimeMs),
|
|
157
|
+
jobsPerSecond: Number(jobsPerSecond.toFixed(1)),
|
|
158
|
+
jobsPerMinute: Math.round(jobsPerMinute),
|
|
159
|
+
timestamp: new Date().toISOString(),
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Analizuje metryki i rekomenduje zmianę concurrency
|
|
164
|
+
* Bazuje na activeCount zamiast waiting (event-driven)
|
|
165
|
+
*/
|
|
166
|
+
analyzeAndRecommendConcurrency() {
|
|
167
|
+
const currentMetrics = {
|
|
168
|
+
activeCount: this.activeCount,
|
|
169
|
+
completedCount: this.completedCount,
|
|
170
|
+
avgProcessingTimeMs: Math.round(this.processingTimes.reduce((sum, time) => sum + time, 0) / this.processingTimes.length),
|
|
171
|
+
};
|
|
172
|
+
// Oblicz średnią activeCount z historii
|
|
173
|
+
const avgActiveCount = this.activeCountHistory.reduce((sum, count) => sum + count, 0) /
|
|
174
|
+
this.activeCountHistory.length;
|
|
175
|
+
// Analiza trendu activeCount
|
|
176
|
+
// Jeśli activeCount konsekwentnie wysoki → worker jest pod obciążeniem → zwiększ concurrency
|
|
177
|
+
// Jeśli activeCount konsekwentnie niski → worker ma nadmiar → zmniejsz concurrency
|
|
178
|
+
const highActiveThreshold = 0.8; // 80% historii z wysokim activeCount
|
|
179
|
+
const lowActiveThreshold = 0.3; // 30% historii z niskim activeCount
|
|
180
|
+
const highActiveRatio = this.activeCountHistory.filter((count) => count >= avgActiveCount * 0.9).length /
|
|
181
|
+
this.activeCountHistory.length;
|
|
182
|
+
const lowActiveRatio = this.activeCountHistory.filter((count) => count <= avgActiveCount * 0.3).length /
|
|
183
|
+
this.activeCountHistory.length;
|
|
184
|
+
// Warunki zwiększenia concurrency
|
|
185
|
+
if (highActiveRatio >= highActiveThreshold && avgActiveCount >= 5) {
|
|
186
|
+
return {
|
|
187
|
+
shouldAdjust: true,
|
|
188
|
+
direction: 'increase',
|
|
189
|
+
reason: `Wysoki activeCount: średnia=${avgActiveCount.toFixed(1)}, ratio=${(highActiveRatio * 100).toFixed(0)}%`,
|
|
190
|
+
currentMetrics,
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
// Warunki zmniejszenia concurrency
|
|
194
|
+
if (lowActiveRatio >= lowActiveThreshold && avgActiveCount >= 1) {
|
|
195
|
+
return {
|
|
196
|
+
shouldAdjust: true,
|
|
197
|
+
direction: 'decrease',
|
|
198
|
+
reason: `Niski activeCount: średnia=${avgActiveCount.toFixed(1)}, ratio=${(lowActiveRatio * 100).toFixed(0)}%`,
|
|
199
|
+
currentMetrics,
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
// Stabilna sytuacja - brak rekomendacji
|
|
203
|
+
return {
|
|
204
|
+
shouldAdjust: false,
|
|
205
|
+
direction: 'none',
|
|
206
|
+
reason: `Stabilne activeCount: średnia=${avgActiveCount.toFixed(1)}`,
|
|
207
|
+
currentMetrics,
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* Zapisuje snapshot activeCount do historii dla analizy trendów
|
|
212
|
+
*/
|
|
213
|
+
recordActiveCountSnapshot() {
|
|
214
|
+
this.activeCountHistory.push(this.activeCount);
|
|
215
|
+
// Ogranicz rozmiar historii
|
|
216
|
+
if (this.activeCountHistory.length > this.maxActiveCountHistory) {
|
|
217
|
+
this.activeCountHistory.shift();
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
/**
|
|
221
|
+
* Resetuje okno profilowania - czyści wszystkie zebrane metryki
|
|
222
|
+
*/
|
|
223
|
+
resetProfilingWindow() {
|
|
224
|
+
this.logger.log(`Reset okna profilowania ${this.commandName}`, {
|
|
225
|
+
commandName: this.commandName,
|
|
226
|
+
windowDurationMs: Date.now() - this.profilingWindowStartTime,
|
|
227
|
+
completedJobs: this.completedCount,
|
|
228
|
+
failedJobs: this.failedCount,
|
|
229
|
+
timestamp: new Date().toISOString(),
|
|
230
|
+
});
|
|
231
|
+
// Reset liczników
|
|
232
|
+
this.completedCount = 0;
|
|
233
|
+
this.failedCount = 0;
|
|
234
|
+
this.processingTimes = [];
|
|
235
|
+
this.activeCountHistory = [];
|
|
236
|
+
// activeCount NIE resetujemy - to bieżąca liczba aktywnych jobów
|
|
237
|
+
// Rozpocznij nowe okno
|
|
238
|
+
this.profilingWindowStartTime = Date.now();
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
exports.default = WorkerMetricsCollector;
|
|
242
|
+
//# sourceMappingURL=worker-metrics-collector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worker-metrics-collector.js","sourceRoot":"","sources":["../../../src/command-bus/worker/worker-metrics-collector.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,26 +2,45 @@ import { Worker } from 'bullmq';
|
|
|
2
2
|
import type { Redis } from 'ioredis';
|
|
3
3
|
import type { ILogger } from '../../shared/types';
|
|
4
4
|
import type JobProcessor from '../job/job-processor';
|
|
5
|
+
import type QueueManager from '../queue/queue-manager';
|
|
5
6
|
/**
|
|
6
7
|
* Zarządza workerami BullMQ dla obsługi komend
|
|
7
8
|
*/
|
|
8
9
|
export default class WorkerOrchestrator {
|
|
9
10
|
private readonly redisConnection;
|
|
10
11
|
private readonly jobProcessor;
|
|
11
|
-
private readonly
|
|
12
|
+
private readonly queueManager;
|
|
13
|
+
private readonly defaultConcurrency;
|
|
12
14
|
private readonly maxAttempts;
|
|
13
15
|
private readonly logger;
|
|
14
16
|
/**
|
|
15
17
|
* Workery BullMQ dla obsługi komend
|
|
16
18
|
*/
|
|
17
19
|
private workers;
|
|
18
|
-
|
|
20
|
+
/**
|
|
21
|
+
* Collectory metryk dla każdego workera
|
|
22
|
+
*/
|
|
23
|
+
private metricsCollectors;
|
|
24
|
+
/**
|
|
25
|
+
* Concurrency per-worker (ustalone przez benchmark)
|
|
26
|
+
*/
|
|
27
|
+
private workerConcurrency;
|
|
28
|
+
/**
|
|
29
|
+
* Timestamp ostatniej zmiany concurrency per-worker (dla cooldown 30s)
|
|
30
|
+
*/
|
|
31
|
+
private lastConcurrencyChange;
|
|
32
|
+
/**
|
|
33
|
+
* Cooldown między zmianami concurrency (30s)
|
|
34
|
+
*/
|
|
35
|
+
private readonly concurrencyCooldownMs;
|
|
36
|
+
constructor(redisConnection: Redis, jobProcessor: JobProcessor, queueManager: QueueManager, defaultConcurrency: number, maxAttempts: number, logger: ILogger);
|
|
19
37
|
/**
|
|
20
38
|
* Rejestruje handler dla komendy i tworzy workera
|
|
39
|
+
* Uruchamia benchmark aby ustalić optymalne concurrency
|
|
21
40
|
* Reużywa własne Redis connection dla optymalizacji pamięci
|
|
22
41
|
* @param commandName - Nazwa komendy
|
|
23
42
|
*/
|
|
24
|
-
registerWorker(commandName: string): void
|
|
43
|
+
registerWorker(commandName: string): Promise<void>;
|
|
25
44
|
/**
|
|
26
45
|
* Konfiguruje event handlery dla workera
|
|
27
46
|
* Memory optimization: redukcja captured variables w closures
|
|
@@ -33,9 +52,15 @@ export default class WorkerOrchestrator {
|
|
|
33
52
|
*/
|
|
34
53
|
getWorker(commandName: string): Worker | undefined;
|
|
35
54
|
/**
|
|
36
|
-
* Zamyka wszystkie workery
|
|
55
|
+
* Zamyka wszystkie workery i czyści collectory metryk
|
|
37
56
|
*/
|
|
38
57
|
closeAll(): Promise<void>;
|
|
58
|
+
/**
|
|
59
|
+
* Dynamicznie dostosowuje concurrency workera na podstawie metryk
|
|
60
|
+
* Zmiana: +/-20% za każdym razem, z cooldown 30s
|
|
61
|
+
* Limity: min 10, max 2000
|
|
62
|
+
*/
|
|
63
|
+
adjustConcurrency(commandName: string, direction: 'increase' | 'decrease', reason: string): void;
|
|
39
64
|
/**
|
|
40
65
|
* Zwraca statystyki workerów (dla diagnostyki)
|
|
41
66
|
*/
|
|
@@ -8,54 +8,104 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
8
8
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
9
|
});
|
|
10
10
|
};
|
|
11
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
+
};
|
|
11
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
15
|
const bullmq_1 = require("bullmq");
|
|
16
|
+
const worker_metrics_collector_1 = __importDefault(require("./worker-metrics-collector"));
|
|
17
|
+
const worker_benchmark_1 = __importDefault(require("./worker-benchmark"));
|
|
13
18
|
/**
|
|
14
19
|
* Zarządza workerami BullMQ dla obsługi komend
|
|
15
20
|
*/
|
|
16
21
|
class WorkerOrchestrator {
|
|
17
|
-
constructor(redisConnection, jobProcessor,
|
|
22
|
+
constructor(redisConnection, jobProcessor, queueManager, defaultConcurrency, maxAttempts, logger) {
|
|
18
23
|
this.redisConnection = redisConnection;
|
|
19
24
|
this.jobProcessor = jobProcessor;
|
|
20
|
-
this.
|
|
25
|
+
this.queueManager = queueManager;
|
|
26
|
+
this.defaultConcurrency = defaultConcurrency;
|
|
21
27
|
this.maxAttempts = maxAttempts;
|
|
22
28
|
this.logger = logger;
|
|
23
29
|
/**
|
|
24
30
|
* Workery BullMQ dla obsługi komend
|
|
25
31
|
*/
|
|
26
32
|
this.workers = {};
|
|
33
|
+
/**
|
|
34
|
+
* Collectory metryk dla każdego workera
|
|
35
|
+
*/
|
|
36
|
+
this.metricsCollectors = {};
|
|
37
|
+
/**
|
|
38
|
+
* Concurrency per-worker (ustalone przez benchmark)
|
|
39
|
+
*/
|
|
40
|
+
this.workerConcurrency = {};
|
|
41
|
+
/**
|
|
42
|
+
* Timestamp ostatniej zmiany concurrency per-worker (dla cooldown 30s)
|
|
43
|
+
*/
|
|
44
|
+
this.lastConcurrencyChange = {};
|
|
45
|
+
/**
|
|
46
|
+
* Cooldown między zmianami concurrency (30s)
|
|
47
|
+
*/
|
|
48
|
+
this.concurrencyCooldownMs = 30000;
|
|
27
49
|
}
|
|
28
50
|
/**
|
|
29
51
|
* Rejestruje handler dla komendy i tworzy workera
|
|
52
|
+
* Uruchamia benchmark aby ustalić optymalne concurrency
|
|
30
53
|
* Reużywa własne Redis connection dla optymalizacji pamięci
|
|
31
54
|
* @param commandName - Nazwa komendy
|
|
32
55
|
*/
|
|
33
56
|
registerWorker(commandName) {
|
|
34
|
-
|
|
35
|
-
|
|
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
|
|
57
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
58
|
+
if (this.workers[commandName]) {
|
|
59
|
+
throw new Error(`Worker dla komendy ${commandName} już istnieje`);
|
|
50
60
|
}
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
61
|
+
// Uruchom benchmark aby ustalić optymalne concurrency
|
|
62
|
+
const benchmark = new worker_benchmark_1.default(commandName, this.redisConnection, this.jobProcessor, this.logger);
|
|
63
|
+
const benchmarkResult = yield benchmark.run();
|
|
64
|
+
const optimalConcurrency = benchmarkResult.recommendedConcurrency;
|
|
65
|
+
// Zapisz per-worker concurrency
|
|
66
|
+
this.workerConcurrency[commandName] = optimalConcurrency;
|
|
67
|
+
this.logger.log('Benchmark zakończony - tworzę workera', {
|
|
68
|
+
commandName,
|
|
69
|
+
oldConcurrency: this.defaultConcurrency,
|
|
70
|
+
newConcurrency: optimalConcurrency,
|
|
71
|
+
benchmarkResult,
|
|
72
|
+
timestamp: new Date().toISOString(),
|
|
73
|
+
});
|
|
74
|
+
// Utwórz workera z optymalnym concurrency
|
|
75
|
+
this.workers[commandName] = new bullmq_1.Worker(`{${commandName}}`, (job) => __awaiter(this, void 0, void 0, function* () {
|
|
76
|
+
try {
|
|
77
|
+
return yield this.jobProcessor.process(job, commandName);
|
|
78
|
+
}
|
|
79
|
+
catch (error) {
|
|
80
|
+
// Top-level error boundary - zapobiega crashom workera
|
|
81
|
+
this.logger.error('Worker handler critical error', {
|
|
82
|
+
commandName,
|
|
83
|
+
jobId: job.id,
|
|
84
|
+
error: error instanceof Error ? error.message : String(error),
|
|
85
|
+
timestamp: new Date().toISOString(),
|
|
86
|
+
});
|
|
87
|
+
throw error; // BullMQ retry mechanism
|
|
88
|
+
}
|
|
89
|
+
}), {
|
|
90
|
+
connection: this.redisConnection,
|
|
91
|
+
concurrency: optimalConcurrency,
|
|
92
|
+
});
|
|
93
|
+
// WAŻNE: Utwórz metrics collector PRZED setupWorkerEventHandlers
|
|
94
|
+
// Aby był dostępny w event handlerach workera
|
|
95
|
+
const metricsCollector = new worker_metrics_collector_1.default(commandName, this.logger,
|
|
96
|
+
// Callback wywoływany gdy MetricsCollector rekomenduje zmianę concurrency
|
|
97
|
+
(recommendation) => {
|
|
98
|
+
if (recommendation.direction !== 'none') {
|
|
99
|
+
this.adjustConcurrency(commandName, recommendation.direction, recommendation.reason);
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
this.metricsCollectors[commandName] = metricsCollector;
|
|
103
|
+
// Skonfiguruj event handlery (wymaga istniejącego metricsCollector)
|
|
104
|
+
this.setupWorkerEventHandlers(commandName);
|
|
105
|
+
this.logger.log(`Worker zarejestrowany dla komendy ${commandName}`, {
|
|
106
|
+
concurrency: optimalConcurrency,
|
|
107
|
+
timestamp: new Date().toISOString(),
|
|
108
|
+
});
|
|
59
109
|
});
|
|
60
110
|
}
|
|
61
111
|
/**
|
|
@@ -66,6 +116,9 @@ class WorkerOrchestrator {
|
|
|
66
116
|
const worker = this.workers[commandName];
|
|
67
117
|
const logger = this.logger;
|
|
68
118
|
const maxAttempts = this.maxAttempts;
|
|
119
|
+
const metricsCollector = this.metricsCollectors[commandName];
|
|
120
|
+
// Tracking czasu przetwarzania dla metryk
|
|
121
|
+
const jobStartTimes = new Map();
|
|
69
122
|
worker.on('failed', (job, err) => {
|
|
70
123
|
var _a, _b, _c, _d, _e;
|
|
71
124
|
const command = job === null || job === void 0 ? void 0 : job.data;
|
|
@@ -79,9 +132,48 @@ class WorkerOrchestrator {
|
|
|
79
132
|
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
133
|
timestamp: new Date().toISOString(),
|
|
81
134
|
});
|
|
135
|
+
// Event-driven metrics - job nieudany
|
|
136
|
+
if ((job === null || job === void 0 ? void 0 : job.id) && metricsCollector) {
|
|
137
|
+
metricsCollector.onJobFailed(job.id);
|
|
138
|
+
}
|
|
139
|
+
// Wyczyść tracking czasu dla failed jobs
|
|
140
|
+
if (job === null || job === void 0 ? void 0 : job.id) {
|
|
141
|
+
jobStartTimes.delete(job.id);
|
|
142
|
+
}
|
|
82
143
|
});
|
|
83
144
|
worker.on('completed', (job) => {
|
|
84
145
|
const command = job === null || job === void 0 ? void 0 : job.data;
|
|
146
|
+
// Oblicz czas przetwarzania i przekaż do metrics collector
|
|
147
|
+
try {
|
|
148
|
+
if ((job === null || job === void 0 ? void 0 : job.id) && jobStartTimes.has(job.id)) {
|
|
149
|
+
const startTime = jobStartTimes.get(job.id);
|
|
150
|
+
const processingTime = Date.now() - startTime;
|
|
151
|
+
// Event-driven metrics - przekaż czas przetwarzania
|
|
152
|
+
if (metricsCollector) {
|
|
153
|
+
metricsCollector.onJobCompleted(job.id, processingTime);
|
|
154
|
+
}
|
|
155
|
+
jobStartTimes.delete(job.id);
|
|
156
|
+
}
|
|
157
|
+
else if (job === null || job === void 0 ? void 0 : job.id) {
|
|
158
|
+
logger.warn('Brak czasu startu dla joba - pomijam metryki czasu', {
|
|
159
|
+
commandName,
|
|
160
|
+
jobId: job.id,
|
|
161
|
+
timestamp: new Date().toISOString(),
|
|
162
|
+
});
|
|
163
|
+
// Wywołaj z czasem 0 aby nie tracić licznika completed
|
|
164
|
+
if (metricsCollector && (job === null || job === void 0 ? void 0 : job.id)) {
|
|
165
|
+
metricsCollector.onJobCompleted(job.id, 0);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
catch (error) {
|
|
170
|
+
logger.error('Błąd podczas przetwarzania metryk joba', {
|
|
171
|
+
commandName,
|
|
172
|
+
jobId: job === null || job === void 0 ? void 0 : job.id,
|
|
173
|
+
error: error instanceof Error ? error.message : String(error),
|
|
174
|
+
timestamp: new Date().toISOString(),
|
|
175
|
+
});
|
|
176
|
+
}
|
|
85
177
|
logger.log('Job zakończony pomyślnie', {
|
|
86
178
|
commandName,
|
|
87
179
|
commandId: command === null || command === void 0 ? void 0 : command.__id,
|
|
@@ -92,6 +184,14 @@ class WorkerOrchestrator {
|
|
|
92
184
|
});
|
|
93
185
|
worker.on('active', (job) => {
|
|
94
186
|
const command = job === null || job === void 0 ? void 0 : job.data;
|
|
187
|
+
// Zapisz czas rozpoczęcia dla tracking przetwarzania
|
|
188
|
+
if (job === null || job === void 0 ? void 0 : job.id) {
|
|
189
|
+
jobStartTimes.set(job.id, Date.now());
|
|
190
|
+
// Event-driven metrics - job aktywowany
|
|
191
|
+
if (metricsCollector) {
|
|
192
|
+
metricsCollector.onJobActive(job.id);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
95
195
|
logger.debug('Job rozpoczęty', {
|
|
96
196
|
commandName,
|
|
97
197
|
commandId: command === null || command === void 0 ? void 0 : command.__id,
|
|
@@ -133,17 +233,83 @@ class WorkerOrchestrator {
|
|
|
133
233
|
return this.workers[commandName];
|
|
134
234
|
}
|
|
135
235
|
/**
|
|
136
|
-
* Zamyka wszystkie workery
|
|
236
|
+
* Zamyka wszystkie workery i czyści collectory metryk
|
|
137
237
|
*/
|
|
138
238
|
closeAll() {
|
|
139
239
|
return __awaiter(this, void 0, void 0, function* () {
|
|
140
240
|
const workers = Object.values(this.workers);
|
|
241
|
+
// Event-driven collectors nie wymagają stop() - nie mają setInterval
|
|
141
242
|
// Usuń wszystkie event listeners PRZED zamknięciem workerów
|
|
142
243
|
// Zapobiega memory leakom z closures i referencjami do handlery
|
|
143
244
|
workers.forEach((worker) => worker.removeAllListeners());
|
|
144
245
|
// Zamknij workery
|
|
145
246
|
yield Promise.all(workers.map((worker) => worker.close()));
|
|
146
247
|
this.workers = {};
|
|
248
|
+
this.metricsCollectors = {};
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
/**
|
|
252
|
+
* Dynamicznie dostosowuje concurrency workera na podstawie metryk
|
|
253
|
+
* Zmiana: +/-20% za każdym razem, z cooldown 30s
|
|
254
|
+
* Limity: min 10, max 2000
|
|
255
|
+
*/
|
|
256
|
+
adjustConcurrency(commandName, direction, reason) {
|
|
257
|
+
var _a, _b;
|
|
258
|
+
const worker = this.workers[commandName];
|
|
259
|
+
if (!worker) {
|
|
260
|
+
this.logger.warn('Nie można dostosować concurrency - worker nie istnieje', {
|
|
261
|
+
commandName,
|
|
262
|
+
timestamp: new Date().toISOString(),
|
|
263
|
+
});
|
|
264
|
+
return;
|
|
265
|
+
}
|
|
266
|
+
// Sprawdź cooldown
|
|
267
|
+
const now = Date.now();
|
|
268
|
+
const lastChange = (_a = this.lastConcurrencyChange[commandName]) !== null && _a !== void 0 ? _a : 0;
|
|
269
|
+
const timeSinceLastChange = now - lastChange;
|
|
270
|
+
if (timeSinceLastChange < this.concurrencyCooldownMs) {
|
|
271
|
+
this.logger.debug('Cooldown aktywny - pomijam zmianę concurrency', {
|
|
272
|
+
commandName,
|
|
273
|
+
timeSinceLastChangeMs: timeSinceLastChange,
|
|
274
|
+
cooldownMs: this.concurrencyCooldownMs,
|
|
275
|
+
timestamp: new Date().toISOString(),
|
|
276
|
+
});
|
|
277
|
+
return;
|
|
278
|
+
}
|
|
279
|
+
const currentConcurrency = (_b = this.workerConcurrency[commandName]) !== null && _b !== void 0 ? _b : this.defaultConcurrency;
|
|
280
|
+
let newConcurrency;
|
|
281
|
+
// Oblicz nową wartość (+/-20%)
|
|
282
|
+
if (direction === 'increase') {
|
|
283
|
+
newConcurrency = Math.round(currentConcurrency * 1.2);
|
|
284
|
+
}
|
|
285
|
+
else {
|
|
286
|
+
newConcurrency = Math.round(currentConcurrency * 0.8);
|
|
287
|
+
}
|
|
288
|
+
// Zastosuj limity: min 10, max 2000
|
|
289
|
+
newConcurrency = Math.max(10, Math.min(2000, newConcurrency));
|
|
290
|
+
// Jeśli wartość się nie zmieniła (np. już na limicie), pomiń
|
|
291
|
+
if (newConcurrency === currentConcurrency) {
|
|
292
|
+
this.logger.debug('Concurrency bez zmian - osiągnięto limit', {
|
|
293
|
+
commandName,
|
|
294
|
+
currentConcurrency,
|
|
295
|
+
attemptedDirection: direction,
|
|
296
|
+
timestamp: new Date().toISOString(),
|
|
297
|
+
});
|
|
298
|
+
return;
|
|
299
|
+
}
|
|
300
|
+
// Zastosuj nową wartość
|
|
301
|
+
worker.concurrency = newConcurrency;
|
|
302
|
+
this.workerConcurrency[commandName] = newConcurrency;
|
|
303
|
+
this.lastConcurrencyChange[commandName] = now;
|
|
304
|
+
const changePercent = ((newConcurrency - currentConcurrency) / currentConcurrency) * 100;
|
|
305
|
+
this.logger.log('Dynamiczna zmiana concurrency', {
|
|
306
|
+
commandName,
|
|
307
|
+
oldConcurrency: currentConcurrency,
|
|
308
|
+
newConcurrency,
|
|
309
|
+
change: `${changePercent > 0 ? '+' : ''}${changePercent.toFixed(0)}%`,
|
|
310
|
+
direction,
|
|
311
|
+
reason,
|
|
312
|
+
timestamp: new Date().toISOString(),
|
|
147
313
|
});
|
|
148
314
|
}
|
|
149
315
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"worker-orchestrator.js","sourceRoot":"","sources":["../../../src/command-bus/worker/worker-orchestrator.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"worker-orchestrator.js","sourceRoot":"","sources":["../../../src/command-bus/worker/worker-orchestrator.ts"],"names":[],"mappings":"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"}
|