pp-command-bus 1.2.0 → 1.2.2

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.
Files changed (30) hide show
  1. package/dist/command-bus/command-bus.spec.js +13 -0
  2. package/dist/command-bus/command-bus.spec.js.map +1 -1
  3. package/dist/command-bus/config/command-bus-config.d.ts +6 -0
  4. package/dist/command-bus/config/command-bus-config.js +4 -0
  5. package/dist/command-bus/config/command-bus-config.js.map +1 -1
  6. package/dist/command-bus/index.js +7 -5
  7. package/dist/command-bus/index.js.map +1 -1
  8. package/dist/command-bus/job/job-processor.d.ts +5 -2
  9. package/dist/command-bus/job/job-processor.js +15 -4
  10. package/dist/command-bus/job/job-processor.js.map +1 -1
  11. package/dist/command-bus/job/job-processor.spec.js +26 -8
  12. package/dist/command-bus/job/job-processor.spec.js.map +1 -1
  13. package/dist/command-bus/rpc/index.d.ts +3 -0
  14. package/dist/command-bus/rpc/index.js +4 -1
  15. package/dist/command-bus/rpc/index.js.map +1 -1
  16. package/dist/command-bus/rpc/payload-compression.service.d.ts +32 -0
  17. package/dist/command-bus/rpc/payload-compression.service.js +109 -0
  18. package/dist/command-bus/rpc/payload-compression.service.js.map +1 -0
  19. package/dist/command-bus/rpc/payload-compression.service.spec.d.ts +1 -0
  20. package/dist/command-bus/rpc/payload-compression.service.spec.js +233 -0
  21. package/dist/command-bus/rpc/payload-compression.service.spec.js.map +1 -0
  22. package/dist/command-bus/rpc/rpc-coordinator.d.ts +45 -27
  23. package/dist/command-bus/rpc/rpc-coordinator.js +255 -178
  24. package/dist/command-bus/rpc/rpc-coordinator.js.map +1 -1
  25. package/dist/command-bus/rpc/rpc-coordinator.spec.js +246 -31
  26. package/dist/command-bus/rpc/rpc-coordinator.spec.js.map +1 -1
  27. package/dist/command-bus/types/index.d.ts +14 -2
  28. package/dist/pp-command-bus-1.2.2.tgz +0 -0
  29. package/package.json +1 -1
  30. package/dist/pp-command-bus-1.2.0.tgz +0 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"payload-compression.service.js","sourceRoot":"","sources":["../../../src/command-bus/rpc/payload-compression.service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,233 @@
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 payload_compression_service_1 = __importDefault(require("./payload-compression.service"));
16
+ /**
17
+ * Testy dla PayloadCompressionService
18
+ * Testuje kompresję gzip dla payloadów RPC >threshold
19
+ */
20
+ describe('PayloadCompressionService', () => {
21
+ let service;
22
+ let mockLogger;
23
+ beforeEach(() => {
24
+ mockLogger = {
25
+ debug: jest.fn(),
26
+ log: jest.fn(),
27
+ warn: jest.fn(),
28
+ error: jest.fn(),
29
+ };
30
+ });
31
+ describe('compress()', () => {
32
+ it('nie kompresuje payloadu mniejszego niż threshold (1KB)', () => __awaiter(void 0, void 0, void 0, function* () {
33
+ // Arrange
34
+ service = new payload_compression_service_1.default(1024, mockLogger);
35
+ const smallPayload = { correlationId: 'test-123', result: 'ok', error: null };
36
+ // Act
37
+ const { data, compressed } = yield service.compress(smallPayload);
38
+ // Assert
39
+ expect(compressed).toBe(false);
40
+ expect(data).toBe(JSON.stringify(smallPayload));
41
+ expect(mockLogger.debug).toHaveBeenCalledWith(expect.stringContaining('Payload NIE skompresowany'), expect.objectContaining({
42
+ originalSize: expect.any(Number),
43
+ threshold: 1024,
44
+ }));
45
+ }));
46
+ it('kompresuje payload większy niż threshold (1KB)', () => __awaiter(void 0, void 0, void 0, function* () {
47
+ // Arrange
48
+ service = new payload_compression_service_1.default(1024, mockLogger);
49
+ // Utwórz duży payload >1KB
50
+ const largePayload = {
51
+ correlationId: 'test-456',
52
+ result: Array.from({ length: 100 }, (_, i) => ({
53
+ id: i,
54
+ name: `Item ${i}`,
55
+ description: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit',
56
+ })),
57
+ error: null,
58
+ };
59
+ // Act
60
+ const { data, compressed } = yield service.compress(largePayload);
61
+ // Assert
62
+ expect(compressed).toBe(true);
63
+ expect(data).not.toBe(JSON.stringify(largePayload)); // Skompresowane
64
+ expect(typeof data).toBe('string'); // Base64 string
65
+ expect(mockLogger.debug).toHaveBeenCalledWith(expect.stringContaining('Payload skompresowany'), expect.objectContaining({
66
+ originalSize: expect.any(Number),
67
+ compressedSize: expect.any(Number),
68
+ compressionRatio: expect.any(String),
69
+ }));
70
+ }));
71
+ it('używa niestandardowego threshold (512 bytes)', () => __awaiter(void 0, void 0, void 0, function* () {
72
+ // Arrange
73
+ service = new payload_compression_service_1.default(512, mockLogger);
74
+ const mediumPayload = {
75
+ correlationId: 'test-789',
76
+ result: Array.from({ length: 30 }, (_, i) => ({
77
+ id: i,
78
+ data: 'test data item with more content to exceed 512 bytes threshold',
79
+ })),
80
+ error: null,
81
+ };
82
+ // Act
83
+ const { compressed } = yield service.compress(mediumPayload);
84
+ // Assert - ten payload jest >512B więc powinien być skompresowany
85
+ expect(compressed).toBe(true);
86
+ }));
87
+ it('zawsze kompresuje gdy threshold=0', () => __awaiter(void 0, void 0, void 0, function* () {
88
+ // Arrange
89
+ service = new payload_compression_service_1.default(0, mockLogger);
90
+ const tinyPayload = { result: 'ok' };
91
+ // Act
92
+ const { compressed } = yield service.compress(tinyPayload);
93
+ // Assert
94
+ expect(compressed).toBe(true);
95
+ }));
96
+ it('oblicza compression ratio poprawnie', () => __awaiter(void 0, void 0, void 0, function* () {
97
+ // Arrange
98
+ service = new payload_compression_service_1.default(100, mockLogger);
99
+ const payload = {
100
+ data: Array.from({ length: 50 }, () => 'repeated text for compression test '),
101
+ };
102
+ // Act
103
+ yield service.compress(payload);
104
+ // Assert
105
+ expect(mockLogger.debug).toHaveBeenCalledWith(expect.stringContaining('Payload skompresowany'), expect.objectContaining({
106
+ compressionRatio: expect.stringMatching(/\d+%/), // Format: "XX%"
107
+ }));
108
+ }));
109
+ });
110
+ describe('decompress()', () => {
111
+ it('dekompresuje payload gdy compressed=true', () => __awaiter(void 0, void 0, void 0, function* () {
112
+ // Arrange
113
+ service = new payload_compression_service_1.default(100, mockLogger);
114
+ const originalPayload = {
115
+ correlationId: 'test-999',
116
+ result: {
117
+ status: 'success',
118
+ data: Array.from({ length: 20 }, (_, i) => ({
119
+ id: i,
120
+ value: `item-${i}`,
121
+ description: 'some longer text to make payload bigger',
122
+ })),
123
+ },
124
+ error: null,
125
+ };
126
+ // Najpierw skompresuj
127
+ const { data: compressedData, compressed } = yield service.compress(originalPayload);
128
+ expect(compressed).toBe(true);
129
+ // Act - dekompresuj
130
+ const decompressed = yield service.decompress(compressedData, true);
131
+ // Assert
132
+ expect(decompressed).toEqual(originalPayload);
133
+ }));
134
+ it('parsuje JSON gdy compressed=false', () => __awaiter(void 0, void 0, void 0, function* () {
135
+ // Arrange
136
+ service = new payload_compression_service_1.default(10000, mockLogger); // Bardzo wysoki threshold
137
+ const originalPayload = {
138
+ correlationId: 'test-111',
139
+ result: 'simple result',
140
+ error: null,
141
+ };
142
+ // Kompresuj (ale nie zostanie skompresowany bo <10KB)
143
+ const { data, compressed } = yield service.compress(originalPayload);
144
+ expect(compressed).toBe(false);
145
+ // Act - dekompresuj
146
+ const decompressed = yield service.decompress(data, false);
147
+ // Assert
148
+ expect(decompressed).toEqual(originalPayload);
149
+ }));
150
+ it('rzuca błąd gdy corrupted gzip data', () => __awaiter(void 0, void 0, void 0, function* () {
151
+ // Arrange
152
+ service = new payload_compression_service_1.default(1024, mockLogger);
153
+ const corruptedData = 'invalid-base64-gzip-data!!!';
154
+ // Act & Assert
155
+ yield expect(() => __awaiter(void 0, void 0, void 0, function* () {
156
+ yield service.decompress(corruptedData, true);
157
+ })).rejects.toThrow('Failed to decompress payload');
158
+ expect(mockLogger.error).toHaveBeenCalledWith(expect.stringContaining('Błąd dekompresji'), expect.any(Object));
159
+ }));
160
+ it('rzuca błąd gdy invalid JSON (compressed=false)', () => __awaiter(void 0, void 0, void 0, function* () {
161
+ // Arrange
162
+ service = new payload_compression_service_1.default(1024, mockLogger);
163
+ const invalidJson = '{invalid json}';
164
+ // Act & Assert
165
+ yield expect(() => __awaiter(void 0, void 0, void 0, function* () {
166
+ yield service.decompress(invalidJson, false);
167
+ })).rejects.toThrow();
168
+ }));
169
+ });
170
+ describe('edge cases', () => {
171
+ it('obsługuje pusty payload', () => __awaiter(void 0, void 0, void 0, function* () {
172
+ // Arrange
173
+ service = new payload_compression_service_1.default(1024, mockLogger);
174
+ const emptyPayload = {};
175
+ // Act
176
+ const { data, compressed } = yield service.compress(emptyPayload);
177
+ const decompressed = yield service.decompress(data, compressed);
178
+ // Assert
179
+ expect(decompressed).toEqual(emptyPayload);
180
+ }));
181
+ it('obsługuje payload z null i undefined', () => __awaiter(void 0, void 0, void 0, function* () {
182
+ // Arrange
183
+ service = new payload_compression_service_1.default(1024, mockLogger);
184
+ const payload = { result: null, error: undefined };
185
+ // Act
186
+ const { data, compressed } = yield service.compress(payload);
187
+ const decompressed = yield service.decompress(data, compressed);
188
+ // Assert
189
+ expect(decompressed).toEqual({ result: null, error: undefined });
190
+ }));
191
+ it('obsługuje payload z obiektami zagnieżdżonymi', () => __awaiter(void 0, void 0, void 0, function* () {
192
+ // Arrange
193
+ service = new payload_compression_service_1.default(100, mockLogger);
194
+ const nestedPayload = {
195
+ level1: {
196
+ level2: {
197
+ level3: {
198
+ data: [1, 2, 3],
199
+ },
200
+ },
201
+ },
202
+ };
203
+ // Act
204
+ const { data, compressed } = yield service.compress(nestedPayload);
205
+ const decompressed = yield service.decompress(data, compressed);
206
+ // Assert
207
+ expect(decompressed).toEqual(nestedPayload);
208
+ }));
209
+ it('osiąga compression ratio >50% dla typowego JSON', () => __awaiter(void 0, void 0, void 0, function* () {
210
+ // Arrange
211
+ service = new payload_compression_service_1.default(100, mockLogger);
212
+ const typicalPayload = {
213
+ correlationId: 'abc-123',
214
+ result: Array.from({ length: 50 }, (_, i) => ({
215
+ id: i,
216
+ name: `User ${i}`,
217
+ email: `user${i}@example.com`,
218
+ active: true,
219
+ })),
220
+ error: null,
221
+ };
222
+ // Act
223
+ const { data, compressed } = yield service.compress(typicalPayload);
224
+ // Assert
225
+ expect(compressed).toBe(true);
226
+ const originalSize = Buffer.byteLength(JSON.stringify(typicalPayload), 'utf8');
227
+ const compressedSize = Buffer.byteLength(data, 'utf8');
228
+ const ratio = ((originalSize - compressedSize) / originalSize) * 100;
229
+ expect(ratio).toBeGreaterThan(50); // >50% redukcja
230
+ }));
231
+ });
232
+ });
233
+ //# sourceMappingURL=payload-compression.service.spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"payload-compression.service.spec.js","sourceRoot":"","sources":["../../../src/command-bus/rpc/payload-compression.service.spec.ts"],"names":[],"mappings":"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"}
@@ -2,47 +2,67 @@ import type { Redis } from 'ioredis';
2
2
  import type { ILogger } from '../../shared/types';
3
3
  import type { RpcMetadata } from '../types';
4
4
  import type Command from '../command';
5
+ import type PayloadCompressionService from './payload-compression.service';
5
6
  /**
6
7
  * Zarządza lifecycle wywołań RPC przez Redis Pub/Sub
7
- * Każde wywołanie call() subskrybuje dedykowany kanał dla odpowiedzi
8
- * Odpowiedzi wysyłane przez redis.publish() zamiast kolejek BullMQ
8
+ * Używa shared subscriber z pattern matching dla izolacji między procesami
9
+ * Multiplexing odpowiedzi przez Map<correlationId, PendingCall>
10
+ *
11
+ * Architektura: Jeden shared subscriber per proces
12
+ * - Eliminuje race conditions (subscriber zawsze gotowy)
13
+ * - Jedno połączenie Redis zamiast N per RPC call
14
+ * - Pattern: rpc:response:{processId}:* dla izolacji między replikami
15
+ * - Multiplexing przez Map dla routingu odpowiedzi do promises
9
16
  */
10
17
  export default class RpcCoordinator {
11
18
  private readonly logger;
12
19
  private readonly redisConnection;
20
+ private readonly compressionService;
13
21
  /**
14
- * Pool reużywalnych Redis subscribers
15
- * Maksymalnie 20 subscribers w puli dla optymalizacji pamięci
22
+ * UUID procesu Node.js (współdzielony przez wszystkie instancje w procesie)
16
23
  */
17
- private subscriberPool;
24
+ private readonly processInstanceId;
18
25
  /**
19
- * Maksymalna wielkość puli subscribers
26
+ * Shared subscriber dla wszystkich RPC calls w tym procesie
20
27
  */
21
- private readonly maxPoolSize;
22
- constructor(logger: ILogger, redisConnection: Redis);
28
+ private sharedSubscriber;
23
29
  /**
24
- * Pobiera subscriber z puli lub tworzy nowy
25
- * @returns Redis subscriber instance
30
+ * Mapa pending RPC calls - routing odpowiedzi do promises
26
31
  */
27
- private acquireSubscriber;
32
+ private pendingCalls;
28
33
  /**
29
- * Zwraca subscriber do puli lub zamyka jeśli pula pełna
30
- * @param subscriber - Subscriber do zwrócenia
34
+ * Czy subscriber jest gotowy (psubscribe zakończony)
31
35
  */
32
- private releaseSubscriber;
36
+ private isSubscriberReady;
37
+ /**
38
+ * Promise dla oczekiwania na gotowość subscribera
39
+ */
40
+ private subscriberReadyPromise;
41
+ constructor(logger: ILogger, redisConnection: Redis, compressionService: PayloadCompressionService);
42
+ /**
43
+ * Konfiguruje shared subscriber dla wszystkich RPC calls
44
+ * Pattern subscribe: rpc:response:{processId}:* dla izolacji między procesami
45
+ * Multiplexing: pmessage handler routuje do odpowiednich pending calls
46
+ */
47
+ private setupSharedSubscriber;
33
48
  /**
34
49
  * Przygotowuje komendę RPC z odpowiednimi metadanymi
35
50
  * @param command - Komenda do wysłania
36
- * @param responseChannel - Nazwa kanału Redis Pub/Sub dla odpowiedzi
51
+ * @param responseChannel - Nazwa kanału Redis Pub/Sub dla odpowiedzi (z processInstanceId)
37
52
  * @returns Komenda z metadanymi RPC
38
53
  */
39
54
  prepareRpcCommand<T extends Command>(command: T, responseChannel: string): T & {
40
55
  __rpcMetadata: RpcMetadata;
41
56
  };
42
57
  /**
43
- * Rejestruje nowe wywołanie RPC z timeout przez Redis Pub/Sub
44
- * Subskrybuje dedykowany kanał dla odpowiedzi
45
- * Automatycznie czyści subscriber po zakończeniu (sukces/błąd/timeout)
58
+ * Rejestruje nowe wywołanie RPC z timeout przez shared subscriber
59
+ * Dodaje pending call do Map i zwraca promise
60
+ * Subscriber jest zawsze gotowy (subskrybuje przy konstrukcji) - zero race conditions
61
+ *
62
+ * Architektura: Shared subscriber + multiplexing
63
+ * - Brak race conditions (subscriber gotowy przed pierwszym call)
64
+ * - Jedno połączenie Redis per proces
65
+ * - Routing przez Map<correlationId, PendingCall>
46
66
  *
47
67
  * @param correlationId - Unikalny ID wywołania
48
68
  * @param commandName - Nazwa komendy
@@ -51,18 +71,16 @@ export default class RpcCoordinator {
51
71
  */
52
72
  registerCall<T>(correlationId: string, commandName: string, timeout: number): Promise<T>;
53
73
  /**
54
- * Czyści subscriber po zakończeniu RPC call
55
- * Unsubscribe z grace period (100ms) i zwrot do puli
56
- * Fail-safe - nie rzuca błędów, tylko loguje
74
+ * Obsługuje wiadomość RPC z Redis Pub/Sub (pmessage handler)
75
+ * Ekstraktuje correlationId, znajduje pending call, dekompresuje i resolve/reject
57
76
  *
58
- * @param subscriber - Subscriber do wyczyszczenia
59
- * @param responseChannel - Kanał do unsubscribe
60
- * @param correlationId - ID wywołania (dla logowania)
77
+ * @param channel - Pełna nazwa kanału: rpc:response:{processId}:{correlationId}
78
+ * @param message - Skompresowana odpowiedź RPC (JSON)
61
79
  */
62
- private cleanupSubscriber;
80
+ private handleRpcMessage;
63
81
  /**
64
- * Zamyka wszystkie subscribers z puli i czyści zasoby
65
- * Wywołane przy zamykaniu CommandBus
82
+ * Zamyka RpcCoordinator i czyści zasoby
83
+ * Reject wszystkie pending calls i zamknij shared subscriber
66
84
  */
67
85
  close(): Promise<void>;
68
86
  }