pp-command-bus 1.2.3 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -4,39 +4,207 @@ Distributed Command Bus library supporting RPC and job queuing with BullMQ for R
4
4
 
5
5
  ## Opis
6
6
 
7
- **pp-command-bus** to biblioteka do obsługi rozproszonych komend zgodna ze wzorcem **CQRS (Command Query Responsibility Segregation)**. Wspiera:
7
+ **pp-command-bus** to zaawansowana biblioteka do obsługi rozproszonych komend zgodna ze wzorcem **CQRS (Command Query Responsibility Segregation)**. Zapewnia wysoką wydajność, automatyczną optymalizację i zaawansowane funkcje produkcyjne.
8
+
9
+ ### Kluczowe Cechy
8
10
 
9
11
  - ✅ **Fire-and-forget commands** - wysyłanie komend bez oczekiwania na wynik
10
- - ✅ **RPC (Remote Procedure Call)** - synchroniczne wywołania z oczekiwaniem na odpowiedź
12
+ - ✅ **RPC (Remote Procedure Call)** - synchroniczne wywołania przez Redis Pub/Sub z oczekiwaniem na odpowiedź
13
+ - ✅ **Automatyczna kompresja** - gzip dla payloadów RPC >1KB (konfigurowalne)
14
+ - ✅ **Auto-optymalizacja** - dynamiczne dostosowywanie concurrency na podstawie CPU/RAM
15
+ - ✅ **Process isolation** - izolacja odpowiedzi RPC między procesami Node.js
11
16
  - ✅ **Job queuing** - kolejkowanie zadań z retry, backoff i delayed execution
12
17
  - ✅ **BullMQ integration** - wydajna kolejka zadań na Redis/DragonflyDB
13
18
  - ✅ **TypeScript** - pełne wsparcie typów i strict mode
14
19
  - ✅ **Memory leak protection** - zaawansowana diagnostyka i cleanup
15
- - ✅ **Command logging** - opcjonalne logowanie komend do plików
16
- - ✅ **Modularna architektura** - komponenty zgodne z zasadami SOLID i SRP
20
+ - ✅ **Command logging** - opcjonalne logowanie komend do plików JSONL
21
+ - ✅ **Modularna architektura** - komponenty zgodne z zasadami SOLID, DDD i SRP
17
22
 
18
- ## Struktura Projektu
23
+ ## Architektura Systemu
24
+
25
+ ### Diagram Komponentów
19
26
 
20
27
  ```
21
- src/
22
- ├── command-bus/ # Główna logika CommandBus
23
- ├── config/ # Konfiguracja CommandBus
24
- ├── job/ # Przetwarzanie jobów i opcje
25
- ├── logging/ # Command logging do plików
26
- ├── queue/ # Queue management i cache
27
- ├── rpc/ # RPC coordination
28
- ├── worker/ # Worker orchestration
29
- ├── types/ # Typy TypeScript
30
- ├── docs/ # Dokumentacja architektury
31
- ├── command.ts # Klasa bazowa Command
32
- └── index.ts # CommandBus główna klasa
33
- ├── shared/ # Wspólne komponenty
34
- ├── config/ # Base config z Redis
35
- ├── logging/ # Logger wrapper z poziomami
36
- │ └── types.ts # Współdzielone typy
37
- ├── examples/ # Przykłady użycia
38
- │ └── rpc.demo.ts # Demo RPC calls
39
- └── index.ts # Główny export pakietu
28
+ ┌─────────────────────────────────────────────────────────────────────┐
29
+ CommandBus
30
+ ┌────────────────┐ ┌──────────────┐ ┌─────────────────────────┐
31
+ │ QueueManager │ │ RpcCoordinator│ │ WorkerOrchestrator │
32
+ - Cache kolejek│ │ - Pub/Sub │ │ - Dynamiczne concurrency│
33
+ - BullMQ Queue │ │ - Process ID │ │ - Worker benchmark │ │
34
+ └────────┬───────┘ └──────┬───────┘ └────────┬────────────────┘
35
+ │ │ │ │
36
+ │ │ │
37
+ ┌────────▼──────────────────▼────────────────────▼───────────────┐
38
+ │ JobProcessor (Command Handler Execution) │
39
+ │ - Kompresja/dekompresja payloadów │
40
+ │ │ - Wykonywanie handlerów │
41
+ │ - Wysyłanie odpowiedzi RPC przez Pub/Sub │ │
42
+ └──────────────────────────┬──────────────────────────────────────┘
43
+ └─────────────────────────────┼────────────────────────────────────────┘
44
+
45
+ ┌─────────▼──────────┐
46
+ │ PayloadCompression
47
+ │ Service │
48
+ │ - gzip compression │
49
+ │ - threshold: 1KB │
50
+ └─────────────────────┘
51
+ ```
52
+
53
+ ### Główne Serwisy
54
+
55
+ #### 1. **CommandBus** (główna klasa orkiestrująca)
56
+ - **Odpowiedzialność**: Główny punkt wejścia dla użytkownika, orkiestracja wszystkich komponentów
57
+ - **Metody publiczne**:
58
+ - `dispatch(command)` - wysyłanie fire-and-forget
59
+ - `call(command, timeout)` - synchroniczne RPC
60
+ - `handle(commandClass, handler)` - rejestracja handlerów
61
+ - `close()` - graceful shutdown
62
+ - **Zarządzanie połączeniami**: 3 dedykowane połączenia Redis (Queue, Worker, RPC)
63
+
64
+ #### 2. **RpcCoordinator** (zarządzanie RPC)
65
+ - **Odpowiedzialność**: Zarządzanie cyklem życia wywołań RPC przez Redis Pub/Sub
66
+ - **Kluczowe funkcje**:
67
+ - **Shared Subscriber** - jeden subscriber dla wszystkich RPC calls (pattern matching)
68
+ - **Process Isolation** - UUID procesu Node.js dla izolacji odpowiedzi między procesami
69
+ - **Timeout Management** - automatyczne cleanup po timeout
70
+ - **Multiplexing** - routing odpowiedzi do odpowiednich promises
71
+ - **Kanały**: `rpc:response:{processId}:{correlationId}`
72
+
73
+ #### 3. **WorkerOrchestrator** (orkiestracja workerów)
74
+ - **Odpowiedzialność**: Zarządzanie workerami BullMQ i dynamiczna optymalizacja
75
+ - **Kluczowe funkcje**:
76
+ - **WorkerBenchmark** - automatyczny benchmark przy rejestracji handlera
77
+ - **WorkerMetricsCollector** - event-driven metrics collection
78
+ - **Dynamic Concurrency** - dostosowywanie concurrency +/-20% co 30s
79
+ - **Event Handlers** - obsługa zdarzeń: active, completed, failed, stalled
80
+ - **Limity concurrency**: min 10, max 2000
81
+
82
+ #### 4. **JobProcessor** (wykonywanie handlerów)
83
+ - **Odpowiedzialność**: Wykonywanie handlerów komend i obsługa odpowiedzi RPC
84
+ - **Flow przetwarzania**:
85
+ 1. Dekompresja payloadu (jeśli skompresowany)
86
+ 2. Rekonstrukcja obiektów Date
87
+ 3. Opcjonalne logowanie komendy
88
+ 4. Wykonanie handlera
89
+ 5. Wysłanie odpowiedzi RPC przez Pub/Sub (jeśli RPC)
90
+ - **Kompresja odpowiedzi**: automatyczna kompresja przez PayloadCompressionService
91
+
92
+ #### 5. **QueueManager** (zarządzanie kolejkami)
93
+ - **Odpowiedzialność**: Cache kolejek BullMQ dla optymalizacji pamięci
94
+ - **Funkcje**:
95
+ - `getOrCreateQueue(commandName)` - lazy loading kolejek
96
+ - `closeAllQueues()` - graceful shutdown wszystkich kolejek
97
+ - **Naming**: `{CommandName}` jako nazwa kolejki
98
+
99
+ #### 6. **PayloadCompressionService** (kompresja)
100
+ - **Odpowiedzialność**: Automatyczna kompresja/dekompresja payloadów gzip
101
+ - **Threshold**: 1024 bajty (1KB) domyślnie, konfigurowalne przez ENV
102
+ - **Metody**:
103
+ - `compressCommand(command)` - dodaje flagę `__compressed`
104
+ - `decompressCommand(command)` - dekompresja i usunięcie flagi
105
+ - `compress(data)` - generyczna kompresja do base64
106
+ - `decompress(data, compressed)` - generyczna dekompresja
107
+ - **Współdzielony serwis**: jedna instancja dla całego CommandBus
108
+
109
+ #### 7. **CommandLogger** (opcjonalne logowanie)
110
+ - **Odpowiedzialność**: Persystencja komend do plików JSONL
111
+ - **Format**: `{timestamp}.jsonl` - rotacja co godzinę
112
+ - **Zawartość**: pełny payload komendy z metadanymi
113
+ - **Aktywacja**: przez ENV `COMMAND_BUS_LOG=./command-logs`
114
+
115
+ #### 8. **AutoConfigOptimizer** (auto-optymalizacja)
116
+ - **Odpowiedzialność**: Obliczanie optymalnego concurrency na podstawie zasobów systemowych
117
+ - **Heurystyka**:
118
+ - I/O-heavy workload (Redis/BullMQ)
119
+ - `concurrency = CPU cores * 2 + (availableMemory / 512MB)`
120
+ - Zakładane 512MB RAM per worker
121
+ - **Aktywacja**: domyślnie włączone (ENV `COMMAND_BUS_AUTO_OPTIMIZE=false` wyłącza)
122
+
123
+ ### Flow Przepływu Danych
124
+
125
+ #### Flow 1: dispatch() - Fire-and-forget
126
+
127
+ ```
128
+ User Code
129
+
130
+ ├─→ 1. commandBus.dispatch(command)
131
+
132
+ ├─→ 2. PayloadCompressionService.compressCommand(command)
133
+ │ └─→ Jeśli payload >1KB → gzip → base64 → __compressed: true
134
+
135
+ ├─→ 3. QueueManager.getOrCreateQueue(commandName)
136
+ │ └─→ Cache hit/miss → zwraca Queue
137
+
138
+ ├─→ 4. queue.add(commandName, compressedCommand, options)
139
+ │ └─→ BullMQ dodaje job do Redis
140
+
141
+ └─→ 5. Promise<void> resolved (nie czekamy na wynik)
142
+
143
+ Worker Side (asynchronicznie)
144
+
145
+ ├─→ 6. Worker pobiera job z kolejki
146
+
147
+ ├─→ 7. JobProcessor.process(job)
148
+ │ ├─→ Dekompresja (jeśli __compressed)
149
+ │ ├─→ Rekonstrukcja Date
150
+ │ ├─→ Opcjonalne logowanie (CommandLogger)
151
+ │ └─→ Wykonanie handlera
152
+
153
+ └─→ 8. Worker kończy job (success/fail)
154
+ ```
155
+
156
+ #### Flow 2: call() - RPC przez Redis Pub/Sub
157
+
158
+ ```
159
+ User Code
160
+
161
+ ├─→ 1. commandBus.call(command, timeout)
162
+
163
+ ├─→ 2. RpcCoordinator.registerCall(correlationId, commandName, timeout)
164
+ │ ├─→ Oczekiwanie na gotowość shared subscriber (5s timeout)
165
+ │ ├─→ Utworzenie Promise<T> dla odpowiedzi
166
+ │ ├─→ Zapisanie pending call w Map
167
+ │ └─→ Zwrócenie responsePromise (bez blokowania)
168
+
169
+ ├─→ 3. PayloadCompressionService.compressCommand(command)
170
+ │ └─→ Jeśli payload >1KB → gzip → __compressed: true
171
+
172
+ ├─→ 4. RpcCoordinator.prepareRpcCommand(compressedCommand)
173
+ │ └─→ Dodaje __rpcMetadata: { correlationId, responseChannel, timestamp }
174
+
175
+ ├─→ 5. QueueManager.getOrCreateQueue(commandName)
176
+ │ └─→ Cache hit/miss → zwraca Queue
177
+
178
+ ├─→ 6. queue.add(commandName, commandWithMetadata, options)
179
+ │ └─→ BullMQ dodaje job do Redis
180
+
181
+ └─→ 7. await responsePromise (czeka na odpowiedź z Worker)
182
+
183
+ Worker Side
184
+
185
+ ├─→ 8. Worker pobiera job z kolejki
186
+
187
+ ├─→ 9. JobProcessor.process(job)
188
+ │ ├─→ Dekompresja payloadu (jeśli __compressed)
189
+ │ ├─→ Rekonstrukcja Date
190
+ │ ├─→ Wykonanie handlera → result
191
+ │ │
192
+ │ └─→ 10. JobProcessor.sendRpcResponse(rpcMetadata, result, null)
193
+ │ ├─→ PayloadCompressionService.compress({ correlationId, result, error })
194
+ │ ├─→ Wrapper: { data, compressed }
195
+ │ └─→ redis.publish(responseChannel, JSON.stringify(wrapper))
196
+
197
+ Shared Subscriber (RpcCoordinator)
198
+
199
+ ├─→ 11. pmessage event → handleRpcMessage(channel, message)
200
+ │ ├─→ Ekstraktuj correlationId z channel
201
+ │ ├─→ Weryfikuj processInstanceId (process isolation)
202
+ │ ├─→ Znajdź pending call w Map
203
+ │ ├─→ PayloadCompressionService.decompress(wrapper.data, wrapper.compressed)
204
+ │ ├─→ resolve(result) lub reject(error)
205
+ │ └─→ Cleanup: clearTimeout, delete z Map
206
+
207
+ └─→ 12. User Code otrzymuje wynik → Promise<T> resolved
40
208
  ```
41
209
 
42
210
  ## Instalacja
@@ -116,31 +284,164 @@ const result = await commandBus.call<{ userId: string }>(command, 5000); // time
116
284
  console.log(`User created with ID: ${result.userId}`);
117
285
  ```
118
286
 
287
+ ## Zmienne Środowiskowe
288
+
289
+ Biblioteka wspiera konfigurację poprzez zmienne środowiskowe z prefiksem `COMMAND_BUS_` (z fallbackiem do starszych nazw `EVENT_BUS_*`):
290
+
291
+ ### Kompletna Lista Zmiennych
292
+
293
+ | Zmienna | Typ | Wartość Domyślna | Opis |
294
+ |---------|-----|------------------|------|
295
+ | `REDIS_URL` | string | `redis://localhost:6379` | URL połączenia Redis/DragonflyDB (wspiera username, password, db) |
296
+ | `LOG_LEVEL` | enum | `log` | Poziom logowania: `debug`, `log`, `warn`, `error` |
297
+ | `COMMAND_BUS_CONCURRENCY` | number | `1` (lub auto) | Liczba równoległych workerów do przetwarzania komend |
298
+ | `COMMAND_BUS_MAX_ATTEMPTS` | number | `3` | Maksymalna liczba prób przetworzenia zadania |
299
+ | `COMMAND_BUS_BACKOFF_DELAY` | number | `2000` | Opóźnienie między próbami w milisekundach |
300
+ | `COMMAND_BUS_QUEUE_MODE` | enum | `fifo` | Tryb przetwarzania kolejki: `fifo` (First In First Out) lub `lifo` (Last In First Out) |
301
+ | `COMMAND_BUS_LOG` | string | _(puste)_ | Ścieżka do katalogu logów komend (JSONL format, rotacja co godzinę) |
302
+ | `COMMAND_BUS_AUTO_OPTIMIZE` | boolean | `true` | Włącz auto-optymalizację concurrency na podstawie CPU/RAM |
303
+ | `COMMAND_BUS_COMPRESSION_THRESHOLD` | number | `1024` | Próg kompresji gzip dla payloadów RPC w bajtach (1KB domyślnie) |
304
+
305
+ ### Fallback do Starszych Nazw
306
+
307
+ Dla kompatybilności wstecznej obsługiwane są również prefiksy `EVENT_BUS_*`:
308
+
309
+ - `EVENT_BUS_CONCURRENCY` → `COMMAND_BUS_CONCURRENCY`
310
+ - `EVENT_BUS_MAX_ATTEMPTS` → `COMMAND_BUS_MAX_ATTEMPTS`
311
+ - `EVENT_BUS_BACKOFF_DELAY` → `COMMAND_BUS_BACKOFF_DELAY`
312
+ - `EVENT_BUS_QUEUE_MODE` → `COMMAND_BUS_QUEUE_MODE`
313
+ - `EVENT_BUS_LOG` → `COMMAND_BUS_LOG`
314
+
315
+ ### Przykład Konfiguracji .env
316
+
317
+ ```bash
318
+ # Połączenie Redis
319
+ REDIS_URL=redis://username:password@localhost:6379/0
320
+
321
+ # Poziom logowania
322
+ LOG_LEVEL=log # debug | log | warn | error
323
+
324
+ # Auto-optymalizacja (domyślnie włączona)
325
+ COMMAND_BUS_AUTO_OPTIMIZE=true
326
+
327
+ # Concurrency (opcjonalnie - auto-optymalizacja ustawi optymalną wartość)
328
+ # COMMAND_BUS_CONCURRENCY=10
329
+
330
+ # Retry i backoff
331
+ COMMAND_BUS_MAX_ATTEMPTS=5 # Maksymalna liczba prób
332
+ COMMAND_BUS_BACKOFF_DELAY=3000 # Opóźnienie między próbami (3s)
333
+
334
+ # Tryb kolejki
335
+ COMMAND_BUS_QUEUE_MODE=fifo # fifo lub lifo
336
+
337
+ # Kompresja payloadów (próg w bajtach)
338
+ COMMAND_BUS_COMPRESSION_THRESHOLD=2048 # 2KB (domyślnie 1KB)
339
+
340
+ # Logowanie komend do plików
341
+ COMMAND_BUS_LOG=./command-logs # Ścieżka do katalogu logów
342
+ ```
343
+
344
+ ### Priorytety Konfiguracji
345
+
346
+ 1. **Parametry konstruktora** - najwyższy priorytet
347
+ 2. **Zmienne środowiskowe** - średni priorytet
348
+ 3. **Wartości domyślne** - najniższy priorytet
349
+
350
+ ```typescript
351
+ // Przykład: parametry konstruktora nadpisują ENV
352
+ const config = new CommandBusConfig({
353
+ redisUrl: 'redis://localhost:6379',
354
+ concurrency: 20, // Nadpisuje COMMAND_BUS_CONCURRENCY
355
+ autoOptimize: false, // Wyłącza auto-optymalizację
356
+ });
357
+ ```
358
+
119
359
  ## Konfiguracja zaawansowana
120
360
 
121
- ### Opcje Redis
361
+ ### Auto-optymalizacja Concurrency
362
+
363
+ Auto-optymalizacja automatycznie oblicza optymalną wartość concurrency na podstawie zasobów systemowych:
122
364
 
123
365
  ```typescript
366
+ // Auto-optymalizacja włączona (domyślnie)
124
367
  const config = new CommandBusConfig({
125
- redisUrl: 'redis://username:password@localhost:6379/0',
126
- // Parsuje się do:
127
- // - host: localhost
128
- // - port: 6379
129
- // - username: username (opcjonalnie)
130
- // - password: password (opcjonalnie)
131
- // - db: 0 (opcjonalnie)
368
+ redisUrl: 'redis://localhost:6379',
369
+ autoOptimize: true, // Domyślnie true
370
+ // concurrency zostanie obliczone jako: CPU cores * 2 + (availableMemory / 512MB)
371
+ });
372
+
373
+ // Wyłączenie auto-optymalizacji
374
+ const config2 = new CommandBusConfig({
375
+ redisUrl: 'redis://localhost:6379',
376
+ autoOptimize: false,
377
+ concurrency: 10, // Ręczna wartość
132
378
  });
133
379
  ```
134
380
 
381
+ **Algorytm auto-optymalizacji**:
382
+ ```
383
+ concurrency = (CPU cores * 2) + Math.floor(availableMemory / 512MB)
384
+
385
+ Przykład:
386
+ - 8 CPU cores
387
+ - 16GB RAM dostępne
388
+ - concurrency = (8 * 2) + Math.floor(16384 / 512) = 16 + 32 = 48
389
+ ```
390
+
391
+ ### Kompresja Payloadów
392
+
393
+ Automatyczna kompresja gzip dla payloadów RPC większych niż threshold:
394
+
395
+ ```typescript
396
+ const config = new CommandBusConfig({
397
+ redisUrl: 'redis://localhost:6379',
398
+ compressionThreshold: 2048, // 2KB (domyślnie 1KB)
399
+ });
400
+
401
+ // Przykład: payload 3KB zostanie automatycznie skompresowany
402
+ const largeCommand = new ProcessReportCommand(largeData); // 3KB
403
+ const result = await commandBus.call(largeCommand); // Automatyczna kompresja/dekompresja
404
+ ```
405
+
406
+ **Korzyści kompresji**:
407
+ - Redukcja transferu danych przez Redis
408
+ - Szybsze przesyłanie dużych payloadów
409
+ - Niższe zużycie pamięci Redis
410
+ - Transparent dla użytkownika (automatyczna dekompresja)
411
+
135
412
  ### Command Logging
136
413
 
137
- Logowanie komend do plików (lokalizacja katalogu):
414
+ Logowanie komend do plików JSONL (rotacja co godzinę):
138
415
 
139
416
  ```typescript
140
417
  const config = new CommandBusConfig({
141
418
  redisUrl: 'redis://localhost:6379',
142
419
  commandLog: './command-logs', // Ścieżka do katalogu logów
143
420
  });
421
+
422
+ // Struktura plików:
423
+ // ./command-logs/2025-01-27T10.jsonl
424
+ // ./command-logs/2025-01-27T11.jsonl
425
+ ```
426
+
427
+ **Format JSONL (JSON Lines)**:
428
+ ```json
429
+ {"__name":"CreateUserCommand","__id":"uuid","__time":1706347200000,"email":"jan@example.com","name":"Jan"}
430
+ {"__name":"ProcessOrderCommand","__id":"uuid","__time":1706347201000,"orderId":"12345"}
431
+ ```
432
+
433
+ ### Opcje Redis
434
+
435
+ ```typescript
436
+ const config = new CommandBusConfig({
437
+ redisUrl: 'redis://username:password@localhost:6379/0',
438
+ // Parsuje się do:
439
+ // - host: localhost
440
+ // - port: 6379
441
+ // - username: username (opcjonalnie)
442
+ // - password: password (opcjonalnie)
443
+ // - db: 0 (opcjonalnie)
444
+ });
144
445
  ```
145
446
 
146
447
  ### Concurrency i Retry
@@ -148,19 +449,18 @@ const config = new CommandBusConfig({
148
449
  ```typescript
149
450
  const config = new CommandBusConfig({
150
451
  redisUrl: 'redis://localhost:6379',
151
- concurrency: 10, // Liczba równoległych workerów dla komend
452
+ concurrency: 10, // Liczba równoległych workerów (lub auto)
152
453
  maxAttempts: 5, // Maksymalna liczba prób przetworzenia zadania
153
- backoffDelay: 2000, // Opóźnienie między próbami (ms)
454
+ backoffDelay: 3000, // Opóźnienie między próbami (3s)
154
455
  });
155
456
  ```
156
457
 
157
- ### Tryb kolejki i RPC TTL
458
+ ### Tryb kolejki
158
459
 
159
460
  ```typescript
160
461
  const config = new CommandBusConfig({
161
462
  redisUrl: 'redis://localhost:6379',
162
463
  queueMode: 'fifo', // 'fifo' (First In First Out) lub 'lifo' (Last In First Out)
163
- rpcReplyTtl: 60000, // TTL dla odpowiedzi RPC w milisekundach (1 minuta)
164
464
  });
165
465
  ```
166
466
 
@@ -207,24 +507,46 @@ const config2 = new CommandBusConfig({
207
507
 
208
508
  Wysyła komendę do kolejki bez oczekiwania na wynik (fire-and-forget).
209
509
 
510
+ **Flow**:
511
+ 1. Kompresja payloadu (jeśli >threshold)
512
+ 2. Pobranie/utworzenie kolejki z cache
513
+ 3. Dodanie job do BullMQ
514
+ 4. Natychmiastowy return
515
+
210
516
  ```typescript
211
517
  await commandBus.dispatch(new CreateUserCommand('email@example.com', 'Jan Kowalski'));
212
518
  ```
213
519
 
214
520
  #### `call<T>(command: Command, timeout?: number): Promise<T>`
215
521
 
216
- Wywołuje komendę synchronicznie i czeka na odpowiedź (RPC). Domyślny timeout: 30000ms (30s).
522
+ Wywołuje komendę synchronicznie i czeka na odpowiedź przez Redis Pub/Sub (RPC). Domyślny timeout: 30000ms (30s).
523
+
524
+ **Flow**:
525
+ 1. Rejestracja pending call z timeoutem
526
+ 2. Kompresja payloadu (jeśli >threshold)
527
+ 3. Przygotowanie metadanych RPC (correlationId, responseChannel)
528
+ 4. Dodanie job do BullMQ
529
+ 5. Oczekiwanie na odpowiedź przez shared subscriber
530
+ 6. Dekompresja odpowiedzi
531
+ 7. Zwrócenie wyniku lub błędu
217
532
 
218
533
  ```typescript
219
534
  const result = await commandBus.call<{ userId: string }>(command, 5000);
220
535
  ```
221
536
 
222
- #### `handle<T>(commandClass, handler): Promise<void>`
537
+ #### `handle<T>(commandClass, handler): void`
538
+
539
+ Rejestruje handler dla określonej klasy komendy. Tylko jeden handler per typ komendy.
223
540
 
224
- Rejestruje handler dla określonej klasy komendy.
541
+ **Automatyczne akcje**:
542
+ 1. Rejestracja handlera w Map
543
+ 2. Utworzenie workera BullMQ
544
+ 3. Uruchomienie benchmarku dla optymalnego concurrency
545
+ 4. Utworzenie metrics collector
546
+ 5. Setup event handlers
225
547
 
226
548
  ```typescript
227
- await commandBus.handle(CreateUserCommand, async (command) => {
549
+ commandBus.handle(CreateUserCommand, async (command) => {
228
550
  const user = await createUser(command.email, command.name);
229
551
  return { userId: user.id };
230
552
  });
@@ -232,7 +554,13 @@ await commandBus.handle(CreateUserCommand, async (command) => {
232
554
 
233
555
  #### `close(): Promise<void>`
234
556
 
235
- Zamyka wszystkie połączenia i workery.
557
+ Zamyka wszystkie połączenia i workery z graceful shutdown.
558
+
559
+ **Cleanup**:
560
+ 1. Zamknięcie wszystkich workerów BullMQ
561
+ 2. Zamknięcie wszystkich kolejek z cache
562
+ 3. Zamknięcie RpcCoordinator (reject pending calls)
563
+ 4. Zamknięcie 3 połączeń Redis (Queue, Worker, RPC)
236
564
 
237
565
  ```typescript
238
566
  await commandBus.close();
@@ -250,10 +578,13 @@ class MyCommand extends Command {
250
578
  }
251
579
  ```
252
580
 
253
- Każda komenda ma:
254
- - `__id` - unikalny UUID
255
- - `__name` - nazwa klasy komendy
256
- - `__timestamp` - timestamp utworzenia
581
+ **Właściwości automatyczne**:
582
+ - `__id` - unikalny UUID (randomUUID)
583
+ - `__name` - nazwa klasy komendy (constructor.name)
584
+ - `__time` - timestamp utworzenia (Date.now())
585
+
586
+ **Metody statyczne**:
587
+ - `reconstructDates(obj)` - rekonstrukcja obiektów Date z serializowanych danych
257
588
 
258
589
  ### CommandBusConfig
259
590
 
@@ -264,72 +595,205 @@ interface CommandBusConfigOptions {
264
595
  redisUrl?: string; // URL Redis (domyślnie: 'redis://localhost:6379' lub REDIS_URL)
265
596
  logger?: ILogger; // Logger (domyślnie console)
266
597
  logLevel?: 'debug' | 'log' | 'warn' | 'error'; // Poziom logowania (domyślnie 'log')
267
- concurrency?: number; // Liczba workerów komend (domyślnie 1)
598
+ concurrency?: number; // Liczba workerów (domyślnie 1 lub auto)
268
599
  maxAttempts?: number; // Maksymalna liczba prób (domyślnie 3)
269
600
  backoffDelay?: number; // Opóźnienie między próbami w ms (domyślnie 2000)
270
601
  queueMode?: 'fifo' | 'lifo'; // Tryb kolejki (domyślnie 'fifo')
271
602
  commandLog?: string; // Ścieżka do katalogu logów komend (opcjonalnie)
603
+ autoOptimize?: boolean; // Auto-optymalizacja concurrency (domyślnie true)
604
+ compressionThreshold?: number; // Próg kompresji w bajtach (domyślnie 1024)
272
605
  }
273
606
  ```
274
607
 
275
- ## Migracja z pp-event-bus 1.x
608
+ ## Przykłady Użycia
276
609
 
277
- Jeśli używałeś Command Bus z pakietu `pp-event-bus` w wersji 1.x:
610
+ ### Podstawowy przykład z RPC
278
611
 
279
- ### Przed:
612
+ ```typescript
613
+ import { CommandBus, CommandBusConfig, Command } from 'pp-command-bus';
614
+
615
+ // Definicja komendy
616
+ class CalculateCommand extends Command {
617
+ constructor(
618
+ public readonly a: number,
619
+ public readonly b: number,
620
+ public readonly operation: 'add' | 'multiply',
621
+ ) {
622
+ super();
623
+ }
624
+ }
625
+
626
+ // Konfiguracja
627
+ const config = new CommandBusConfig({
628
+ redisUrl: 'redis://localhost:6379',
629
+ });
630
+ const commandBus = new CommandBus(config);
631
+
632
+ // Rejestracja handlera
633
+ commandBus.handle(CalculateCommand, async (command) => {
634
+ console.log(`Calculating: ${command.a} ${command.operation} ${command.b}`);
635
+
636
+ switch (command.operation) {
637
+ case 'add':
638
+ return command.a + command.b;
639
+ case 'multiply':
640
+ return command.a * command.b;
641
+ }
642
+ });
643
+
644
+ // Fire-and-forget
645
+ await commandBus.dispatch(new CalculateCommand(5, 3, 'add'));
646
+
647
+ // RPC - czekamy na wynik
648
+ const result = await commandBus.call<number>(
649
+ new CalculateCommand(5, 3, 'multiply'),
650
+ 5000 // timeout 5s
651
+ );
652
+ console.log(`Result: ${result}`); // Result: 15
653
+ ```
654
+
655
+ ### Równoległe wywołania RPC
280
656
 
281
657
  ```typescript
282
- import { CommandBus, Command, CommandBusConfig } from 'pp-event-bus';
658
+ // Wiele równoległych RPC calls
659
+ const [result1, result2, result3] = await Promise.all([
660
+ commandBus.call<number>(new CalculateCommand(10, 5, 'add')),
661
+ commandBus.call<UserInfo>(new GetUserInfoCommand('user-1')),
662
+ commandBus.call<ValidationResult>(new ValidateUserCommand('jan@example.com', 30)),
663
+ ]);
664
+
665
+ console.log('All results:', { result1, result2, result3 });
283
666
  ```
284
667
 
285
- ### Po:
668
+ ### Obsługa błędów
286
669
 
287
- ```bash
288
- npm install pp-command-bus
670
+ ```typescript
671
+ commandBus.handle(CreateUserCommand, async (command) => {
672
+ try {
673
+ // Walidacja
674
+ if (!command.email.includes('@')) {
675
+ throw new Error('Invalid email format');
676
+ }
677
+
678
+ const user = await createUser(command.email, command.name);
679
+ return { userId: user.id };
680
+ } catch (error) {
681
+ // Loguj błąd
682
+ console.error('Failed to create user:', error);
683
+
684
+ // Rzuć błąd - BullMQ spróbuje ponownie (maxAttempts)
685
+ throw error;
686
+ }
687
+ });
688
+
689
+ // Obsługa błędów w RPC
690
+ try {
691
+ const result = await commandBus.call(new CreateUserCommand('invalid-email', 'Jan'));
692
+ } catch (error) {
693
+ console.error('RPC failed:', error.message);
694
+ }
289
695
  ```
290
696
 
697
+ ### Graceful Shutdown
698
+
291
699
  ```typescript
292
- import { CommandBus, Command, CommandBusConfig } from 'pp-command-bus';
700
+ process.on('SIGTERM', async () => {
701
+ console.log('Shutting down CommandBus...');
702
+ await commandBus.close();
703
+ process.exit(0);
704
+ });
705
+
706
+ process.on('SIGINT', async () => {
707
+ console.log('Shutting down CommandBus...');
708
+ await commandBus.close();
709
+ process.exit(0);
710
+ });
293
711
  ```
294
712
 
295
- **Pełna zgodność API** - jedyna zmiana to źródło importu.
713
+ ## Zaawansowane Funkcje
296
714
 
297
- ## Zmienne środowiskowe
715
+ ### 1. Dynamiczne Concurrency
298
716
 
299
- Biblioteka wspiera konfigurację poprzez zmienne środowiskowe z prefiksem `COMMAND_BUS_` (z fallbackiem do starszych nazw `EVENT_BUS_*`):
717
+ WorkerOrchestrator automatycznie dostosowuje concurrency na podstawie metryk:
300
718
 
301
- ```bash
302
- # Połączenie Redis
303
- REDIS_URL=redis://localhost:6379
719
+ - **Benchmark przy starcie** - optymalny concurrency dla każdego workera
720
+ - **Event-driven metrics** - zbieranie metryk z workerów
721
+ - **Dynamiczne dostosowanie** - +/-20% co 30s (cooldown)
722
+ - **Limity** - min 10, max 2000
304
723
 
305
- # Poziom logowania
306
- LOG_LEVEL=log # debug | log | warn | error
724
+ ```typescript
725
+ // Automatyczne - benchmark ustali optymalną wartość
726
+ const config = new CommandBusConfig({
727
+ redisUrl: 'redis://localhost:6379',
728
+ // concurrency zostanie ustalone przez benchmark (np. 15-20)
729
+ });
730
+ ```
307
731
 
308
- # Concurrency
309
- COMMAND_BUS_CONCURRENCY=5 # Liczba workerów komend (fallback: EVENT_BUS_CONCURRENCY)
732
+ ### 2. Process Isolation w RPC
310
733
 
311
- # Retry i backoff
312
- COMMAND_BUS_MAX_ATTEMPTS=3 # Maksymalna liczba prób (fallback: EVENT_BUS_MAX_ATTEMPTS)
313
- COMMAND_BUS_BACKOFF_DELAY=2000 # Opóźnienie między próbami w ms (fallback: EVENT_BUS_BACKOFF_DELAY)
734
+ Każdy proces Node.js ma unikalny UUID - odpowiedzi RPC są izolowane między procesami:
314
735
 
315
- # Tryb kolejki
316
- COMMAND_BUS_QUEUE_MODE=fifo # fifo lub lifo (fallback: EVENT_BUS_QUEUE_MODE)
736
+ ```
737
+ Process A (UUID: abc-123):
738
+ - Kanał: rpc:response:abc-123:*
739
+ - Otrzymuje tylko swoje odpowiedzi
317
740
 
318
- # Logowanie komend
319
- COMMAND_BUS_LOG=./command-logs # Ścieżka do katalogu logów (fallback: EVENT_BUS_LOG)
741
+ Process B (UUID: def-456):
742
+ - Kanał: rpc:response:def-456:*
743
+ - Otrzymuje tylko swoje odpowiedzi
320
744
  ```
321
745
 
322
- ### Wartości domyślne
746
+ ### 3. Shared Subscriber Pattern
747
+
748
+ Jeden shared subscriber dla wszystkich RPC calls zamiast N subskrybentów:
323
749
 
324
- | Zmienna | Wartość domyślna | Opis |
325
- |---------|------------------|------|
326
- | `REDIS_URL` | `redis://localhost:6379` | URL połączenia Redis |
327
- | `LOG_LEVEL` | `log` | Poziom logowania |
328
- | `COMMAND_BUS_CONCURRENCY` | `1` | Liczba workerów komend |
329
- | `COMMAND_BUS_MAX_ATTEMPTS` | `3` | Maksymalna liczba prób |
330
- | `COMMAND_BUS_BACKOFF_DELAY` | `2000` | Opóźnienie między próbami (ms) |
331
- | `COMMAND_BUS_QUEUE_MODE` | `fifo` | Tryb kolejki |
332
- | `COMMAND_BUS_LOG` | _(puste)_ | Brak logowania komend |
750
+ **Tradycyjne podejście** (N subskrybentów):
751
+ ```
752
+ 1000 RPC calls 1000 Redis subscriptions duże obciążenie
753
+ ```
754
+
755
+ **Shared Subscriber** (1 subskrybent):
756
+ ```
757
+ 1000 RPC calls 1 Redis pattern subscription → multiplexing w pamięci
758
+ ```
759
+
760
+ ### 4. Automatyczna Kompresja
761
+
762
+ PayloadCompressionService automatycznie kompresuje duże payloady:
763
+
764
+ ```typescript
765
+ // Mała komenda (<1KB) - brak kompresji
766
+ const smallCommand = new CreateUserCommand('jan@example.com', 'Jan');
767
+ await commandBus.call(smallCommand); // Bez kompresji
768
+
769
+ // Duża komenda (>1KB) - automatyczna kompresja
770
+ const largeCommand = new ProcessReportCommand(largeData); // 5KB
771
+ await commandBus.call(largeCommand); // Automatyczna kompresja gzip → base64
772
+ ```
773
+
774
+ **Flagi kompresji**:
775
+ - `__compressed: true` - payload został skompresowany
776
+ - Automatyczna dekompresja w JobProcessor
777
+ - Transparent dla użytkownika
778
+
779
+ ### 5. Command Logging
780
+
781
+ Persystencja wszystkich komend do plików JSONL:
782
+
783
+ ```typescript
784
+ const config = new CommandBusConfig({
785
+ commandLog: './command-logs',
786
+ });
787
+
788
+ // Każda komenda jest logowana do pliku:
789
+ // ./command-logs/2025-01-27T10.jsonl
790
+ ```
791
+
792
+ **Use cases**:
793
+ - Auditing i compliance
794
+ - Replay komend
795
+ - Debugging produkcyjnych problemów
796
+ - Analiza przepływu komend
333
797
 
334
798
  ## Best Practices
335
799
 
@@ -364,42 +828,55 @@ commandBus.handle(CreateUserCommand, async (command) => {
364
828
  });
365
829
  ```
366
830
 
367
- ### 3. Obsługa błędów
831
+ ### 3. Monitorowanie RPC timeoutów
368
832
 
369
833
  ```typescript
370
- commandBus.handle(CreateUserCommand, async (command) => {
371
- try {
372
- const user = await createUser(command.email, command.name);
373
- return { userId: user.id };
374
- } catch (error) {
375
- // Loguj błąd
376
- console.error('Failed to create user:', error);
834
+ // Ustaw timeout dostosowany do czasu przetwarzania komendy
835
+ const shortCommand = new QuickCommand();
836
+ const result1 = await commandBus.call(shortCommand, 1000); // 1s dla szybkich operacji
377
837
 
378
- // Rzuć błąd - BullMQ spróbuje ponownie (maxAttempts)
379
- throw error;
380
- }
381
- });
838
+ const longRunningCommand = new ProcessReportCommand();
839
+ const result2 = await commandBus.call(longRunningCommand, 60000); // 60s dla długich operacji
382
840
  ```
383
841
 
384
- ### 4. Graceful shutdown
842
+ ### 4. Walidacja w handlerach
385
843
 
386
844
  ```typescript
387
- process.on('SIGTERM', async () => {
388
- console.log('Shutting down CommandBus...');
389
- await commandBus.close();
390
- process.exit(0);
845
+ commandBus.handle(CreateUserCommand, async (command) => {
846
+ // Walidacja na początku
847
+ if (!command.email || !command.email.includes('@')) {
848
+ throw new Error('Invalid email');
849
+ }
850
+
851
+ if (!command.name || command.name.length < 2) {
852
+ throw new Error('Invalid name');
853
+ }
854
+
855
+ // Logika biznesowa
856
+ return await createUser(command.email, command.name);
391
857
  });
392
858
  ```
393
859
 
394
- ### 5. Monitorowanie RPC timeoutów
860
+ ### 5. Logowanie kontekstu
395
861
 
396
862
  ```typescript
397
- // Ustaw timeout dostosowany do czasu przetwarzania komendy
398
- const shortCommand = new QuickCommand();
399
- const result1 = await commandBus.call(shortCommand, 1000); // 1s dla szybkich operacji
863
+ commandBus.handle(CreateUserCommand, async (command) => {
864
+ console.log('Processing CreateUserCommand', {
865
+ commandId: command.__id,
866
+ timestamp: command.__time,
867
+ email: command.email,
868
+ });
400
869
 
401
- const longRunningCommand = new ProcessReportCommand();
402
- const result2 = await commandBus.call(longRunningCommand, 60000); // 60s dla długich operacji
870
+ // Logika biznesowa
871
+ const user = await createUser(command.email, command.name);
872
+
873
+ console.log('User created successfully', {
874
+ commandId: command.__id,
875
+ userId: user.id,
876
+ });
877
+
878
+ return { userId: user.id };
879
+ });
403
880
  ```
404
881
 
405
882
  ## Testing
@@ -416,12 +893,13 @@ describe('User Commands', () => {
416
893
  const config = new CommandBusConfig({
417
894
  redisUrl: 'redis://localhost:6379',
418
895
  logger: console,
896
+ logLevel: 'error', // Tylko błędy w testach
419
897
  });
420
898
 
421
899
  commandBus = new CommandBus(config);
422
900
 
423
901
  // Zarejestruj handler
424
- await commandBus.handle(CreateUserCommand, async (command) => {
902
+ commandBus.handle(CreateUserCommand, async (command) => {
425
903
  return { userId: 'test-user-id' };
426
904
  });
427
905
  });
@@ -435,6 +913,24 @@ describe('User Commands', () => {
435
913
  const result = await commandBus.call<{ userId: string }>(command, 5000);
436
914
 
437
915
  expect(result.userId).toBeDefined();
916
+ expect(result.userId).toBe('test-user-id');
917
+ });
918
+
919
+ it('should handle multiple commands in parallel', async () => {
920
+ const commands = [
921
+ new CreateUserCommand('user1@example.com', 'User 1'),
922
+ new CreateUserCommand('user2@example.com', 'User 2'),
923
+ new CreateUserCommand('user3@example.com', 'User 3'),
924
+ ];
925
+
926
+ const results = await Promise.all(
927
+ commands.map((cmd) => commandBus.call<{ userId: string }>(cmd, 5000))
928
+ );
929
+
930
+ expect(results).toHaveLength(3);
931
+ results.forEach((result) => {
932
+ expect(result.userId).toBeDefined();
933
+ });
438
934
  });
439
935
  });
440
936
  ```
@@ -459,7 +955,7 @@ Zwiększ timeout lub sprawdź czy handler został zarejestrowany:
459
955
  const result = await commandBus.call(command, 60000); // 60s
460
956
 
461
957
  // Sprawdź czy handler został zarejestrowany PRZED wywołaniem
462
- await commandBus.handle(MyCommand, async (command) => {
958
+ commandBus.handle(MyCommand, async (command) => {
463
959
  // Handler implementation
464
960
  return { result: 'success' };
465
961
  });
@@ -475,19 +971,102 @@ Upewnij się że handler został zarejestrowany przed wysłaniem komendy:
475
971
  ```typescript
476
972
  // ❌ ŹLE - handler po dispatch
477
973
  await commandBus.dispatch(new MyCommand());
478
- await commandBus.handle(MyCommand, async (cmd) => { ... }); // Za późno!
974
+ commandBus.handle(MyCommand, async (cmd) => { ... }); // Za późno!
479
975
 
480
976
  // ✅ DOBRZE - handler przed dispatch
481
- await commandBus.handle(MyCommand, async (cmd) => { ... });
977
+ commandBus.handle(MyCommand, async (cmd) => { ... });
482
978
  await commandBus.dispatch(new MyCommand()); // Teraz OK
483
979
  ```
484
980
 
485
- ## Licencja
981
+ ### Wysokie zużycie pamięci
486
982
 
487
- MIT
983
+ 1. **Wyłącz command logging** jeśli nie jest potrzebne
984
+ 2. **Zmniejsz concurrency** jeśli workery używają dużo pamięci
985
+ 3. **Zwiększ compressionThreshold** jeśli duże payloady powodują problemy
488
986
 
489
- ## Autorzy
490
- - Mariusz Lejkowski <m.lejkowski@polskiepolisy.pl>
987
+ ```typescript
988
+ const config = new CommandBusConfig({
989
+ commandLog: undefined, // Wyłącz logging
990
+ concurrency: 5, // Zmniejsz concurrency
991
+ compressionThreshold: 512, // Kompresuj już od 512B
992
+ });
993
+ ```
994
+
995
+ ### Worker stalled
996
+
997
+ Worker został zatrzymany (prawdopodobnie crashed). BullMQ automatycznie przeniesie job do innego workera.
998
+
999
+ **Przyczyny**:
1000
+ - Out of memory
1001
+ - Uncaught exception w handlerze
1002
+ - Timeout w handlerze
1003
+
1004
+ **Rozwiązanie**:
1005
+ - Dodaj try/catch w handlerze
1006
+ - Zwiększ pamięć dla procesu
1007
+ - Zmniejsz concurrency
1008
+
1009
+ ## Struktura Projektu
1010
+
1011
+ ```
1012
+ src/
1013
+ ├── command-bus/ # Główna logika CommandBus
1014
+ │ ├── config/ # Konfiguracja CommandBus
1015
+ │ │ ├── command-bus-config.ts
1016
+ │ │ └── auto-config-optimizer.ts
1017
+ │ ├── job/ # Przetwarzanie jobów i opcje
1018
+ │ │ ├── job-processor.ts
1019
+ │ │ └── job-options-builder.ts
1020
+ │ ├── logging/ # Command logging do plików
1021
+ │ │ └── command-logger.ts
1022
+ │ ├── queue/ # Queue management i cache
1023
+ │ │ └── queue-manager.ts
1024
+ │ ├── rpc/ # RPC coordination
1025
+ │ │ ├── rpc-coordinator.ts
1026
+ │ │ └── payload-compression.service.ts
1027
+ │ ├── worker/ # Worker orchestration
1028
+ │ │ ├── worker-orchestrator.ts
1029
+ │ │ ├── worker-benchmark.ts
1030
+ │ │ └── worker-metrics-collector.ts
1031
+ │ ├── types/ # Typy TypeScript
1032
+ │ │ └── index.ts
1033
+ │ ├── command.ts # Klasa bazowa Command
1034
+ │ └── index.ts # CommandBus główna klasa
1035
+ ├── shared/ # Wspólne komponenty
1036
+ │ ├── config/ # Base config z Redis
1037
+ │ │ └── base-config.ts
1038
+ │ ├── logging/ # Logger wrapper z poziomami
1039
+ │ │ ├── logger.ts
1040
+ │ │ └── log-level.ts
1041
+ │ └── types.ts # Współdzielone typy
1042
+ ├── examples/ # Przykłady użycia
1043
+ │ ├── rpc.demo.ts # Demo RPC calls
1044
+ │ ├── rpc-throughput.demo.ts # Demo wydajności RPC
1045
+ │ └── rpc-compression.demo.ts # Demo kompresji
1046
+ └── index.ts # Główny export pakietu
1047
+ ```
1048
+
1049
+ ## Migracja z pp-event-bus 1.x
1050
+
1051
+ Jeśli używałeś Command Bus z pakietu `pp-event-bus` w wersji 1.x:
1052
+
1053
+ ### Przed:
1054
+
1055
+ ```typescript
1056
+ import { CommandBus, Command, CommandBusConfig } from 'pp-event-bus';
1057
+ ```
1058
+
1059
+ ### Po:
1060
+
1061
+ ```bash
1062
+ npm install pp-command-bus
1063
+ ```
1064
+
1065
+ ```typescript
1066
+ import { CommandBus, Command, CommandBusConfig } from 'pp-command-bus';
1067
+ ```
1068
+
1069
+ **Pełna zgodność API** - jedyna zmiana to źródło importu.
491
1070
 
492
1071
  ## Wersjonowanie i Releases
493
1072
 
@@ -528,56 +1107,6 @@ test: dodano testy dla command logging
528
1107
  - `chore:` - inne zmiany (bez release)
529
1108
  - `!` lub `BREAKING CHANGE:` - breaking change (→ major release)
530
1109
 
531
- ### Proces release
532
-
533
- 1. **Commituj zgodnie z konwencją** - husky sprawdzi format commita
534
- 2. **Merge do master** - GitLab CI automatycznie:
535
- - Uruchomi testy i linting
536
- - Zbuduje projekt
537
- - Wygeneruje nową wersję (semantic-release)
538
- - Zaktualizuje CHANGELOG.md
539
- - Opublikuje do npm
540
- - Utworzy GitLab release
541
-
542
- ### Branch model
543
-
544
- - `master` - branch produkcyjny (→ release do npm)
545
- - `beta` - branch pre-release (→ beta release do npm)
546
- - feature branches - tworzenie nowych funkcjonalności
547
-
548
- ### CI/CD Pipeline
549
-
550
- GitLab CI wykonuje następujące etapy:
551
-
552
- **Quality Stage:**
553
- - `lint` - sprawdzenie jakości kodu (ESLint + Prettier)
554
- - `test` - testy jednostkowe i coverage
555
-
556
- **Build Stage:**
557
- - `build` - kompilacja TypeScript do JavaScript
558
-
559
- **Release Stage:**
560
- - `release:production` - automatyczny release z master
561
- - `release:beta` - automatyczny release z beta
562
- - `release:dry-run` - podgląd zmian (manual trigger)
563
-
564
- ### Zmienne środowiskowe w GitLab
565
-
566
- Aby pipeline działał, skonfiguruj w GitLab CI/CD Settings → Variables:
567
-
568
- - `NPM_TOKEN` - token do publikacji w npm (z scope publish)
569
- - `GITLAB_TOKEN` - token do tworzenia release'ów w GitLab
570
-
571
- ### Testowanie release lokalnie
572
-
573
- ```bash
574
- # Podgląd co zostanie wypuszczone
575
- npm run semantic-release:dry-run
576
-
577
- # Sprawdzenie ostatniego release
578
- git tag --sort=-v:refname | head -n 1
579
- ```
580
-
581
1110
  ## Dokumentacja
582
1111
 
583
1112
  ### Architektura
@@ -587,12 +1116,21 @@ Szczegółowa dokumentacja architektury systemu, wzorców projektowych i zasad S
587
1116
 
588
1117
  ### Komponenty
589
1118
 
590
- - **QueueManager** - zarządzanie kolejkami BullMQ i cache reply queues
591
- - **WorkerOrchestrator** - orkiestracja workerów i obsługa zdarzeń
1119
+ - **QueueManager** - zarządzanie kolejkami BullMQ i cache kolejek
1120
+ - **WorkerOrchestrator** - orkiestracja workerów, dynamiczne concurrency, benchmark
592
1121
  - **JobProcessor** - przetwarzanie jobów i wykonanie handlerów
593
- - **RpcCoordinator** - zarządzanie wywołaniami RPC i timeoutami
1122
+ - **RpcCoordinator** - zarządzanie wywołaniami RPC przez Redis Pub/Sub
594
1123
  - **JobOptionsBuilder** - konfiguracja opcji dla jobów BullMQ
595
1124
  - **CommandLogger** - persystencja komend do plików JSONL
1125
+ - **PayloadCompressionService** - automatyczna kompresja gzip
1126
+ - **AutoConfigOptimizer** - optymalizacja concurrency na podstawie zasobów
1127
+
1128
+ ## Licencja
1129
+
1130
+ MIT
1131
+
1132
+ ## Autorzy
1133
+ - Mariusz Lejkowski <m.lejkowski@polskiepolisy.pl>
596
1134
 
597
1135
  ## Linki
598
1136