pp-command-bus 1.1.0 → 1.2.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.
Files changed (46) hide show
  1. package/dist/command-bus/command-bus.spec.js +17 -3
  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.d.ts +1 -2
  7. package/dist/command-bus/index.js +15 -12
  8. package/dist/command-bus/index.js.map +1 -1
  9. package/dist/command-bus/job/job-processor.d.ts +10 -10
  10. package/dist/command-bus/job/job-processor.js +28 -113
  11. package/dist/command-bus/job/job-processor.js.map +1 -1
  12. package/dist/command-bus/job/job-processor.spec.js +28 -107
  13. package/dist/command-bus/job/job-processor.spec.js.map +1 -1
  14. package/dist/command-bus/rpc/index.d.ts +3 -0
  15. package/dist/command-bus/rpc/index.js +4 -1
  16. package/dist/command-bus/rpc/index.js.map +1 -1
  17. package/dist/command-bus/rpc/payload-compression.service.d.ts +32 -0
  18. package/dist/command-bus/rpc/payload-compression.service.js +109 -0
  19. package/dist/command-bus/rpc/payload-compression.service.js.map +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 +35 -16
  23. package/dist/command-bus/rpc/rpc-coordinator.js +138 -89
  24. package/dist/command-bus/rpc/rpc-coordinator.js.map +1 -1
  25. package/dist/command-bus/rpc/rpc-coordinator.spec.js +195 -431
  26. package/dist/command-bus/rpc/rpc-coordinator.spec.js.map +1 -1
  27. package/dist/command-bus/types/index.d.ts +6 -4
  28. package/dist/command-bus/worker/worker-benchmark.d.ts +2 -1
  29. package/dist/command-bus/worker/worker-benchmark.js +34 -41
  30. package/dist/command-bus/worker/worker-benchmark.js.map +1 -1
  31. package/dist/command-bus/worker/worker-benchmark.spec.js +25 -15
  32. package/dist/command-bus/worker/worker-benchmark.spec.js.map +1 -1
  33. package/dist/command-bus/worker/worker-metrics-collector.d.ts +60 -49
  34. package/dist/command-bus/worker/worker-metrics-collector.js +176 -193
  35. package/dist/command-bus/worker/worker-metrics-collector.js.map +1 -1
  36. package/dist/command-bus/worker/worker-orchestrator.d.ts +1 -1
  37. package/dist/command-bus/worker/worker-orchestrator.js +20 -25
  38. package/dist/command-bus/worker/worker-orchestrator.js.map +1 -1
  39. package/dist/command-bus/worker/worker-orchestrator.spec.js +32 -28
  40. package/dist/command-bus/worker/worker-orchestrator.spec.js.map +1 -1
  41. package/dist/pp-command-bus-1.2.1.tgz +0 -0
  42. package/package.json +1 -1
  43. package/dist/command-bus/worker/worker-metrics-collector.spec.js +0 -315
  44. package/dist/command-bus/worker/worker-metrics-collector.spec.js.map +0 -1
  45. package/dist/pp-command-bus-1.1.0.tgz +0 -0
  46. /package/dist/command-bus/{worker/worker-metrics-collector.spec.d.ts → rpc/payload-compression.service.spec.d.ts} +0 -0
@@ -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,30 +2,40 @@ 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 { QueueManager } from 'command-bus/queue';
5
+ import type PayloadCompressionService from './payload-compression.service';
6
6
  /**
7
- * Zarządza lifecycle wywołań RPC bez mapy pending calls
8
- * Każde wywołanie call() tworzy unikalną kolejkę odpowiedzi
9
- * Kolejka jest automatycznie kasowana po otrzymaniu odpowiedzi lub timeout
7
+ * Zarządza lifecycle wywołań RPC przez Redis Pub/Sub
8
+ * Każde wywołanie call() tworzy dedykowany subscriber dla odpowiedzi
9
+ * Odpowiedzi wysyłane przez redis.publish() zamiast kolejek BullMQ
10
+ *
11
+ * Architektura: Każdy RPC call ma własny subscriber (bez poolingu)
12
+ * - Prostsza implementacja bez race conditions
13
+ * - Lepsza skalowalność przy wysokim obciążeniu (brak pool exhaustion)
14
+ * - Redis duplicate() jest lekkie (reużywa connection pool ioredis)
10
15
  */
11
16
  export default class RpcCoordinator {
12
17
  private readonly logger;
13
18
  private readonly redisConnection;
14
- private readonly queueManager;
15
- constructor(logger: ILogger, redisConnection: Redis, queueManager: QueueManager);
19
+ private readonly compressionService;
20
+ constructor(logger: ILogger, redisConnection: Redis, compressionService: PayloadCompressionService);
16
21
  /**
17
22
  * Przygotowuje komendę RPC z odpowiednimi metadanymi
18
23
  * @param command - Komenda do wysłania
19
- * @param replyQueueName - Nazwa kolejki odpowiedzi
24
+ * @param responseChannel - Nazwa kanału Redis Pub/Sub dla odpowiedzi
20
25
  * @returns Komenda z metadanymi RPC
21
26
  */
22
- prepareRpcCommand<T extends Command>(command: T, replyQueueName: string): T & {
27
+ prepareRpcCommand<T extends Command>(command: T, responseChannel: string): T & {
23
28
  __rpcMetadata: RpcMetadata;
24
29
  };
25
30
  /**
26
- * Rejestruje nowe wywołanie RPC z timeout
27
- * Tworzy unikalną kolejkę i worker dla tego wywołania
28
- * Automatycznie czyści zasoby po zakończeniu (sukces/błąd/timeout)
31
+ * Rejestruje nowe wywołanie RPC z timeout przez Redis Pub/Sub
32
+ * Tworzy dedykowany subscriber dla każdego wywołania
33
+ * Automatycznie zamyka subscriber po zakończeniu (sukces/błąd/timeout)
34
+ *
35
+ * Architektura: Każdy call ma własny subscriber
36
+ * - Brak race conditions przy wysokim obciążeniu
37
+ * - Prostsza implementacja bez poolingu
38
+ * - Automatyczne cleanup przez finally block
29
39
  *
30
40
  * @param correlationId - Unikalny ID wywołania
31
41
  * @param commandName - Nazwa komendy
@@ -34,12 +44,21 @@ export default class RpcCoordinator {
34
44
  */
35
45
  registerCall<T>(correlationId: string, commandName: string, timeout: number): Promise<T>;
36
46
  /**
37
- * Czyści zasoby RPC - zamyka worker i usuwa kolejkę
47
+ * Czyści subscriber po zakończeniu RPC call
48
+ * Unsubscribe i zamknięcie dedykowanego subscriber
38
49
  * Fail-safe - nie rzuca błędów, tylko loguje
39
50
  *
40
- * @param worker - Worker do zamknięcia
41
- * @param queue - Kolejka do usunięcia
42
- * @param queueName - Nazwa kolejki (dla logowania)
51
+ * @param subscriber - Subscriber do wyczyszczenia
52
+ * @param responseChannel - Kanał do unsubscribe
53
+ * @param correlationId - ID wywołania (dla logowania)
54
+ */
55
+ private cleanupSubscriber;
56
+ /**
57
+ * Zamyka RpcCoordinator i czyści zasoby
58
+ * Wywołane przy zamykaniu CommandBus
59
+ *
60
+ * Uwaga: Dedykowane subscribers są automatycznie zamykane w finally block registerCall()
61
+ * Ta metoda nie musi już zamykać puli subscribers (pool został usunięty)
43
62
  */
44
- private cleanupRpcResources;
63
+ close(): void;
45
64
  }
@@ -9,35 +9,45 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
9
9
  });
10
10
  };
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
- const bullmq_1 = require("bullmq");
13
12
  /**
14
- * Zarządza lifecycle wywołań RPC bez mapy pending calls
15
- * Każde wywołanie call() tworzy unikalną kolejkę odpowiedzi
16
- * Kolejka jest automatycznie kasowana po otrzymaniu odpowiedzi lub timeout
13
+ * Zarządza lifecycle wywołań RPC przez Redis Pub/Sub
14
+ * Każde wywołanie call() tworzy dedykowany subscriber dla odpowiedzi
15
+ * Odpowiedzi wysyłane przez redis.publish() zamiast kolejek BullMQ
16
+ *
17
+ * Architektura: Każdy RPC call ma własny subscriber (bez poolingu)
18
+ * - Prostsza implementacja bez race conditions
19
+ * - Lepsza skalowalność przy wysokim obciążeniu (brak pool exhaustion)
20
+ * - Redis duplicate() jest lekkie (reużywa connection pool ioredis)
17
21
  */
18
22
  class RpcCoordinator {
19
- constructor(logger, redisConnection, queueManager) {
23
+ constructor(logger, redisConnection, compressionService) {
20
24
  this.logger = logger;
21
25
  this.redisConnection = redisConnection;
22
- this.queueManager = queueManager;
26
+ this.compressionService = compressionService;
23
27
  }
24
28
  /**
25
29
  * Przygotowuje komendę RPC z odpowiednimi metadanymi
26
30
  * @param command - Komenda do wysłania
27
- * @param replyQueueName - Nazwa kolejki odpowiedzi
31
+ * @param responseChannel - Nazwa kanału Redis Pub/Sub dla odpowiedzi
28
32
  * @returns Komenda z metadanymi RPC
29
33
  */
30
- prepareRpcCommand(command, replyQueueName) {
34
+ prepareRpcCommand(command, responseChannel) {
31
35
  return Object.assign(Object.assign({}, command), { __rpcMetadata: {
32
36
  correlationId: command.__id,
33
- replyQueue: replyQueueName,
37
+ responseChannel,
34
38
  timestamp: Date.now(),
39
+ compressed: true, // Zawsze próbujemy kompresji (zależy od threshold)
35
40
  } });
36
41
  }
37
42
  /**
38
- * Rejestruje nowe wywołanie RPC z timeout
39
- * Tworzy unikalną kolejkę i worker dla tego wywołania
40
- * Automatycznie czyści zasoby po zakończeniu (sukces/błąd/timeout)
43
+ * Rejestruje nowe wywołanie RPC z timeout przez Redis Pub/Sub
44
+ * Tworzy dedykowany subscriber dla każdego wywołania
45
+ * Automatycznie zamyka subscriber po zakończeniu (sukces/błąd/timeout)
46
+ *
47
+ * Architektura: Każdy call ma własny subscriber
48
+ * - Brak race conditions przy wysokim obciążeniu
49
+ * - Prostsza implementacja bez poolingu
50
+ * - Automatyczne cleanup przez finally block
41
51
  *
42
52
  * @param correlationId - Unikalny ID wywołania
43
53
  * @param commandName - Nazwa komendy
@@ -46,55 +56,83 @@ class RpcCoordinator {
46
56
  */
47
57
  registerCall(correlationId, commandName, timeout) {
48
58
  return __awaiter(this, void 0, void 0, function* () {
49
- const replyQueueName = `rpc-reply-${correlationId}`;
50
- this.logger.debug('Tworzenie unikalnej kolejki RPC', {
59
+ const responseChannel = `rpc:response:${correlationId}`;
60
+ // Każdy RPC call tworzy własny dedykowany subscriber
61
+ const subscriber = this.redisConnection.duplicate();
62
+ let timeoutId;
63
+ this.logger.debug('Rejestrowanie wywołania RPC przez Pub/Sub', {
51
64
  correlationId,
52
- replyQueueName,
65
+ responseChannel,
53
66
  commandName,
54
67
  timeout: `${timeout}ms`,
55
68
  timestamp: new Date().toISOString(),
56
69
  });
57
- // Utwórz dedykowaną kolejkę dla tego wywołania
58
- const replyQueue = this.queueManager.createQueue(replyQueueName, this.redisConnection);
59
- // Utwórz dedykowany worker dla tej kolejki (concurrency=1, jedna odpowiedź)
60
- let replyWorker;
61
- let timeoutId;
62
70
  try {
63
- // Promise dla odpowiedzi z workera
71
+ // Promise dla odpowiedzi z Redis Pub/Sub
64
72
  const responsePromise = new Promise((resolve, reject) => {
65
- replyWorker = new bullmq_1.Worker(`{${replyQueueName}}`, (job) => {
66
- const { correlationId: jobCorrelationId, result, error } = job.data;
67
- this.logger.debug('Otrzymano odpowiedź RPC', {
68
- correlationId: jobCorrelationId,
69
- hasResult: result !== undefined,
70
- hasError: error !== undefined,
71
- timestamp: new Date().toISOString(),
72
- });
73
- if (error) {
74
- this.logger.error('Wywołanie RPC odrzucone', {
75
- correlationId: jobCorrelationId,
76
- error,
73
+ const messageHandler = (channel, message) => {
74
+ if (channel !== responseChannel)
75
+ return;
76
+ // Dekompresuj i parsuj odpowiedź (async)
77
+ this.compressionService
78
+ .decompress(message, true)
79
+ .then((decompressed) => {
80
+ const { correlationId: responseCorrelationId, result, error, } = decompressed;
81
+ this.logger.debug('Otrzymano odpowiedź RPC przez Pub/Sub', {
82
+ correlationId: responseCorrelationId,
83
+ hasResult: result !== undefined,
84
+ hasError: error !== undefined,
77
85
  timestamp: new Date().toISOString(),
78
86
  });
79
- reject(new Error(error));
80
- }
81
- else {
82
- this.logger.debug('Wywołanie RPC rozwiązane', {
83
- correlationId: jobCorrelationId,
87
+ // Usunięcie handlera po otrzymaniu odpowiedzi
88
+ subscriber.off('message', messageHandler);
89
+ if (error) {
90
+ this.logger.error('Wywołanie RPC odrzucone', {
91
+ correlationId: responseCorrelationId,
92
+ error,
93
+ timestamp: new Date().toISOString(),
94
+ });
95
+ reject(new Error(error));
96
+ }
97
+ else {
98
+ this.logger.debug('Wywołanie RPC rozwiązane', {
99
+ correlationId: responseCorrelationId,
100
+ timestamp: new Date().toISOString(),
101
+ });
102
+ resolve(result);
103
+ }
104
+ })
105
+ .catch((decompressError) => {
106
+ this.logger.error('Błąd dekompresji/parsowania odpowiedzi RPC', {
107
+ correlationId,
108
+ error: decompressError instanceof Error
109
+ ? decompressError.message
110
+ : String(decompressError),
84
111
  timestamp: new Date().toISOString(),
85
112
  });
86
- resolve(result);
87
- }
88
- return Promise.resolve();
89
- }, {
90
- connection: this.redisConnection,
91
- concurrency: 1, // Tylko jedna odpowiedź per wywołanie
92
- });
93
- this.logger.debug('Worker RPC utworzony', {
94
- correlationId,
95
- replyQueueName,
96
- timestamp: new Date().toISOString(),
97
- });
113
+ reject(new Error('Failed to decompress/parse RPC response'));
114
+ });
115
+ };
116
+ // Obsługa błędów Redis
117
+ const errorHandler = (error) => {
118
+ this.logger.error('Błąd Redis subscriber podczas RPC', {
119
+ correlationId,
120
+ error: error.message,
121
+ timestamp: new Date().toISOString(),
122
+ });
123
+ subscriber.off('message', messageHandler);
124
+ subscriber.off('error', errorHandler);
125
+ reject(new Error(`Redis subscriber error: ${error.message}`));
126
+ };
127
+ subscriber.on('message', messageHandler);
128
+ subscriber.on('error', errorHandler);
129
+ });
130
+ // Subskrybuj kanał PRZED wysłaniem komendy (zapobiega race condition)
131
+ yield subscriber.subscribe(responseChannel);
132
+ this.logger.debug('Subskrybowano kanał RPC', {
133
+ correlationId,
134
+ responseChannel,
135
+ timestamp: new Date().toISOString(),
98
136
  });
99
137
  // Promise dla timeout
100
138
  const timeoutPromise = new Promise((_, reject) => {
@@ -116,9 +154,10 @@ class RpcCoordinator {
116
154
  if (timeoutId) {
117
155
  clearTimeout(timeoutId);
118
156
  }
119
- // Cleanup zasobów (zawsze, niezależnie od wyniku)
120
- this.cleanupRpcResources(replyWorker, replyQueue, replyQueueName).catch((error) => {
121
- this.logger.error('Błąd podczas cleanup zasobów RPC', {
157
+ // Cleanup: zamknij dedykowany subscriber
158
+ this.cleanupSubscriber(subscriber, responseChannel, correlationId).catch((error) => {
159
+ this.logger.error('Błąd podczas cleanup subscriber RPC', {
160
+ correlationId,
122
161
  error: error instanceof Error ? error.message : String(error),
123
162
  timestamp: new Date().toISOString(),
124
163
  });
@@ -127,68 +166,78 @@ class RpcCoordinator {
127
166
  });
128
167
  }
129
168
  /**
130
- * Czyści zasoby RPC - zamyka worker i usuwa kolejkę
169
+ * Czyści subscriber po zakończeniu RPC call
170
+ * Unsubscribe i zamknięcie dedykowanego subscriber
131
171
  * Fail-safe - nie rzuca błędów, tylko loguje
132
172
  *
133
- * @param worker - Worker do zamknięcia
134
- * @param queue - Kolejka do usunięcia
135
- * @param queueName - Nazwa kolejki (dla logowania)
173
+ * @param subscriber - Subscriber do wyczyszczenia
174
+ * @param responseChannel - Kanał do unsubscribe
175
+ * @param correlationId - ID wywołania (dla logowania)
136
176
  */
137
- cleanupRpcResources(worker, queue, queueName) {
177
+ cleanupSubscriber(subscriber, responseChannel, correlationId) {
138
178
  return __awaiter(this, void 0, void 0, function* () {
139
- this.logger.debug('Rozpoczynam cleanup zasobów RPC', {
140
- queueName,
179
+ this.logger.debug('Rozpoczynam cleanup subscriber RPC', {
180
+ correlationId,
181
+ responseChannel,
141
182
  timestamp: new Date().toISOString(),
142
183
  });
143
- // Zamknij worker
144
- if (worker) {
145
- try {
146
- yield worker.close();
147
- this.logger.debug('Worker RPC zamknięty', {
148
- queueName,
149
- timestamp: new Date().toISOString(),
150
- });
151
- }
152
- catch (error) {
153
- this.logger.warn('Błąd podczas zamykania Worker RPC', {
154
- queueName,
155
- error: error instanceof Error ? error.message : String(error),
156
- timestamp: new Date().toISOString(),
157
- });
158
- }
159
- }
160
- // Usuń kolejkę całkowicie (obliterate + close)
184
+ // Unsubscribe z timeoutem (200ms max)
161
185
  try {
162
- yield queue.obliterate({ force: true });
163
- this.logger.debug('Kolejka RPC usunięta (obliterate)', {
164
- queueName,
186
+ yield Promise.race([
187
+ subscriber.unsubscribe(responseChannel),
188
+ new Promise((_, reject) => setTimeout(() => reject(new Error('Unsubscribe timeout')), 200)),
189
+ ]);
190
+ this.logger.debug('Unsubscribe z kanału RPC wykonany', {
191
+ correlationId,
192
+ responseChannel,
165
193
  timestamp: new Date().toISOString(),
166
194
  });
167
195
  }
168
196
  catch (error) {
169
- this.logger.warn('Błąd podczas obliterate kolejki RPC', {
170
- queueName,
197
+ this.logger.warn('Błąd podczas unsubscribe z kanału RPC', {
198
+ correlationId,
199
+ responseChannel,
171
200
  error: error instanceof Error ? error.message : String(error),
172
201
  timestamp: new Date().toISOString(),
173
202
  });
174
203
  }
175
- // Zamknij kolejkę
204
+ // Usuń wszystkie event listenery
205
+ subscriber.removeAllListeners('message');
206
+ subscriber.removeAllListeners('error');
207
+ // Zamknij dedykowany subscriber
176
208
  try {
177
- yield queue.close();
178
- this.logger.debug('Kolejka RPC zamknięta', {
179
- queueName,
209
+ yield subscriber.quit();
210
+ this.logger.debug('Subscriber zamknięty', {
211
+ correlationId,
180
212
  timestamp: new Date().toISOString(),
181
213
  });
182
214
  }
183
215
  catch (error) {
184
- this.logger.warn('Błąd podczas zamykania kolejki RPC', {
185
- queueName,
216
+ this.logger.warn('Błąd podczas zamykania subscriber', {
217
+ correlationId,
186
218
  error: error instanceof Error ? error.message : String(error),
187
219
  timestamp: new Date().toISOString(),
188
220
  });
189
221
  }
190
222
  });
191
223
  }
224
+ /**
225
+ * Zamyka RpcCoordinator i czyści zasoby
226
+ * Wywołane przy zamykaniu CommandBus
227
+ *
228
+ * Uwaga: Dedykowane subscribers są automatycznie zamykane w finally block registerCall()
229
+ * Ta metoda nie musi już zamykać puli subscribers (pool został usunięty)
230
+ */
231
+ close() {
232
+ this.logger.debug('Zamykanie RpcCoordinator', {
233
+ timestamp: new Date().toISOString(),
234
+ });
235
+ // Brak zasobów do wyczyszczenia - subscribers są zamykane per-call
236
+ // Główne połączenie Redis (redisConnection) jest zarządzane przez CommandBus
237
+ this.logger.debug('RpcCoordinator zamknięty', {
238
+ timestamp: new Date().toISOString(),
239
+ });
240
+ }
192
241
  }
193
242
  exports.default = RpcCoordinator;
194
243
  //# sourceMappingURL=rpc-coordinator.js.map