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.
- package/dist/command-bus/command-bus.spec.js +13 -0
- package/dist/command-bus/command-bus.spec.js.map +1 -1
- package/dist/command-bus/config/command-bus-config.d.ts +6 -0
- package/dist/command-bus/config/command-bus-config.js +4 -0
- package/dist/command-bus/config/command-bus-config.js.map +1 -1
- package/dist/command-bus/index.js +7 -5
- package/dist/command-bus/index.js.map +1 -1
- package/dist/command-bus/job/job-processor.d.ts +5 -2
- package/dist/command-bus/job/job-processor.js +15 -4
- package/dist/command-bus/job/job-processor.js.map +1 -1
- package/dist/command-bus/job/job-processor.spec.js +26 -8
- package/dist/command-bus/job/job-processor.spec.js.map +1 -1
- package/dist/command-bus/rpc/index.d.ts +3 -0
- package/dist/command-bus/rpc/index.js +4 -1
- package/dist/command-bus/rpc/index.js.map +1 -1
- package/dist/command-bus/rpc/payload-compression.service.d.ts +32 -0
- package/dist/command-bus/rpc/payload-compression.service.js +109 -0
- package/dist/command-bus/rpc/payload-compression.service.js.map +1 -0
- package/dist/command-bus/rpc/payload-compression.service.spec.d.ts +1 -0
- package/dist/command-bus/rpc/payload-compression.service.spec.js +233 -0
- package/dist/command-bus/rpc/payload-compression.service.spec.js.map +1 -0
- package/dist/command-bus/rpc/rpc-coordinator.d.ts +45 -27
- package/dist/command-bus/rpc/rpc-coordinator.js +255 -178
- package/dist/command-bus/rpc/rpc-coordinator.js.map +1 -1
- package/dist/command-bus/rpc/rpc-coordinator.spec.js +246 -31
- package/dist/command-bus/rpc/rpc-coordinator.spec.js.map +1 -1
- package/dist/command-bus/types/index.d.ts +14 -2
- package/dist/pp-command-bus-1.2.2.tgz +0 -0
- package/package.json +1 -1
- package/dist/pp-command-bus-1.2.0.tgz +0 -0
|
@@ -9,72 +9,98 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
9
9
|
});
|
|
10
10
|
};
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
const crypto_1 = require("crypto");
|
|
13
|
+
/**
|
|
14
|
+
* UUID per proces Node.js - współdzielony przez wszystkie instancje CommandBus w tym samym procesie
|
|
15
|
+
* Zapewnia izolację odpowiedzi RPC między różnymi procesami/replikami
|
|
16
|
+
*/
|
|
17
|
+
const PROCESS_INSTANCE_ID = (0, crypto_1.randomUUID)();
|
|
12
18
|
/**
|
|
13
19
|
* Zarządza lifecycle wywołań RPC przez Redis Pub/Sub
|
|
14
|
-
*
|
|
15
|
-
*
|
|
20
|
+
* Używa shared subscriber z pattern matching dla izolacji między procesami
|
|
21
|
+
* Multiplexing odpowiedzi przez Map<correlationId, PendingCall>
|
|
22
|
+
*
|
|
23
|
+
* Architektura: Jeden shared subscriber per proces
|
|
24
|
+
* - Eliminuje race conditions (subscriber zawsze gotowy)
|
|
25
|
+
* - Jedno połączenie Redis zamiast N per RPC call
|
|
26
|
+
* - Pattern: rpc:response:{processId}:* dla izolacji między replikami
|
|
27
|
+
* - Multiplexing przez Map dla routingu odpowiedzi do promises
|
|
16
28
|
*/
|
|
17
29
|
class RpcCoordinator {
|
|
18
|
-
constructor(logger, redisConnection) {
|
|
30
|
+
constructor(logger, redisConnection, compressionService) {
|
|
19
31
|
this.logger = logger;
|
|
20
32
|
this.redisConnection = redisConnection;
|
|
33
|
+
this.compressionService = compressionService;
|
|
21
34
|
/**
|
|
22
|
-
*
|
|
23
|
-
* Maksymalnie 20 subscribers w puli dla optymalizacji pamięci
|
|
35
|
+
* UUID procesu Node.js (współdzielony przez wszystkie instancje w procesie)
|
|
24
36
|
*/
|
|
25
|
-
this.
|
|
37
|
+
this.processInstanceId = PROCESS_INSTANCE_ID;
|
|
26
38
|
/**
|
|
27
|
-
*
|
|
39
|
+
* Mapa pending RPC calls - routing odpowiedzi do promises
|
|
28
40
|
*/
|
|
29
|
-
this.
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
const subscriber = this.subscriberPool.pop();
|
|
37
|
-
if (subscriber) {
|
|
38
|
-
this.logger.debug('Subscriber pobrany z puli', {
|
|
39
|
-
poolSize: this.subscriberPool.length,
|
|
40
|
-
timestamp: new Date().toISOString(),
|
|
41
|
-
});
|
|
42
|
-
return subscriber;
|
|
43
|
-
}
|
|
44
|
-
// Twórz nowy subscriber jako duplikat głównego połączenia
|
|
45
|
-
const newSubscriber = this.redisConnection.duplicate();
|
|
46
|
-
this.logger.debug('Utworzono nowy subscriber', {
|
|
47
|
-
poolSize: this.subscriberPool.length,
|
|
41
|
+
this.pendingCalls = new Map();
|
|
42
|
+
/**
|
|
43
|
+
* Czy subscriber jest gotowy (psubscribe zakończony)
|
|
44
|
+
*/
|
|
45
|
+
this.isSubscriberReady = false;
|
|
46
|
+
this.logger.debug('Inicjalizacja RpcCoordinator', {
|
|
47
|
+
processInstanceId: this.processInstanceId,
|
|
48
48
|
timestamp: new Date().toISOString(),
|
|
49
49
|
});
|
|
50
|
-
|
|
50
|
+
// Setup shared subscriber z pattern matching
|
|
51
|
+
this.setupSharedSubscriber();
|
|
51
52
|
}
|
|
52
53
|
/**
|
|
53
|
-
*
|
|
54
|
-
*
|
|
54
|
+
* Konfiguruje shared subscriber dla wszystkich RPC calls
|
|
55
|
+
* Pattern subscribe: rpc:response:{processId}:* dla izolacji między procesami
|
|
56
|
+
* Multiplexing: pmessage handler routuje do odpowiednich pending calls
|
|
55
57
|
*/
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
58
|
+
setupSharedSubscriber() {
|
|
59
|
+
this.sharedSubscriber = this.redisConnection.duplicate();
|
|
60
|
+
// Pattern subscribe z processInstanceId - tylko dla tego procesu!
|
|
61
|
+
const pattern = `rpc:response:${this.processInstanceId}:*`;
|
|
62
|
+
this.logger.debug('Tworzenie shared subscriber dla RPC', {
|
|
63
|
+
processInstanceId: this.processInstanceId,
|
|
64
|
+
pattern,
|
|
65
|
+
timestamp: new Date().toISOString(),
|
|
66
|
+
});
|
|
67
|
+
// Promise dla oczekiwania na psubscribe
|
|
68
|
+
this.subscriberReadyPromise = new Promise((resolve) => {
|
|
69
|
+
this.sharedSubscriber.once('psubscribe', (subscribePattern, count) => {
|
|
70
|
+
this.logger.debug('Shared subscriber gotowy', {
|
|
71
|
+
processInstanceId: this.processInstanceId,
|
|
72
|
+
pattern: subscribePattern,
|
|
73
|
+
subscriptionCount: count,
|
|
69
74
|
timestamp: new Date().toISOString(),
|
|
70
75
|
});
|
|
71
|
-
|
|
76
|
+
this.isSubscriberReady = true;
|
|
77
|
+
resolve();
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
// Handler dla odpowiedzi RPC - multiplexing do pending calls
|
|
81
|
+
this.sharedSubscriber.on('pmessage', (_pattern, channel, message) => {
|
|
82
|
+
this.handleRpcMessage(channel, message);
|
|
83
|
+
});
|
|
84
|
+
// Handler błędów Redis subscriber
|
|
85
|
+
this.sharedSubscriber.on('error', (error) => {
|
|
86
|
+
this.logger.error('Błąd shared subscriber RPC', {
|
|
87
|
+
processInstanceId: this.processInstanceId,
|
|
88
|
+
error: error.message,
|
|
89
|
+
timestamp: new Date().toISOString(),
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
// Subskrybuj pattern z processInstanceId
|
|
93
|
+
void this.sharedSubscriber.psubscribe(pattern);
|
|
94
|
+
this.logger.debug('Subskrybowanie pattern dla RPC', {
|
|
95
|
+
processInstanceId: this.processInstanceId,
|
|
96
|
+
pattern,
|
|
97
|
+
timestamp: new Date().toISOString(),
|
|
72
98
|
});
|
|
73
99
|
}
|
|
74
100
|
/**
|
|
75
101
|
* Przygotowuje komendę RPC z odpowiednimi metadanymi
|
|
76
102
|
* @param command - Komenda do wysłania
|
|
77
|
-
* @param responseChannel - Nazwa kanału Redis Pub/Sub dla odpowiedzi
|
|
103
|
+
* @param responseChannel - Nazwa kanału Redis Pub/Sub dla odpowiedzi (z processInstanceId)
|
|
78
104
|
* @returns Komenda z metadanymi RPC
|
|
79
105
|
*/
|
|
80
106
|
prepareRpcCommand(command, responseChannel) {
|
|
@@ -82,12 +108,18 @@ class RpcCoordinator {
|
|
|
82
108
|
correlationId: command.__id,
|
|
83
109
|
responseChannel,
|
|
84
110
|
timestamp: Date.now(),
|
|
111
|
+
compressed: true, // Zawsze próbujemy kompresji (zależy od threshold)
|
|
85
112
|
} });
|
|
86
113
|
}
|
|
87
114
|
/**
|
|
88
|
-
* Rejestruje nowe wywołanie RPC z timeout przez
|
|
89
|
-
*
|
|
90
|
-
*
|
|
115
|
+
* Rejestruje nowe wywołanie RPC z timeout przez shared subscriber
|
|
116
|
+
* Dodaje pending call do Map i zwraca promise
|
|
117
|
+
* Subscriber jest zawsze gotowy (subskrybuje przy konstrukcji) - zero race conditions
|
|
118
|
+
*
|
|
119
|
+
* Architektura: Shared subscriber + multiplexing
|
|
120
|
+
* - Brak race conditions (subscriber gotowy przed pierwszym call)
|
|
121
|
+
* - Jedno połączenie Redis per proces
|
|
122
|
+
* - Routing przez Map<correlationId, PendingCall>
|
|
91
123
|
*
|
|
92
124
|
* @param correlationId - Unikalny ID wywołania
|
|
93
125
|
* @param commandName - Nazwa komendy
|
|
@@ -96,175 +128,220 @@ class RpcCoordinator {
|
|
|
96
128
|
*/
|
|
97
129
|
registerCall(correlationId, commandName, timeout) {
|
|
98
130
|
return __awaiter(this, void 0, void 0, function* () {
|
|
99
|
-
const responseChannel = `rpc:response:${correlationId}`;
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
this.logger.debug('Rejestrowanie wywołania RPC przez Pub/Sub', {
|
|
131
|
+
const responseChannel = `rpc:response:${this.processInstanceId}:${correlationId}`;
|
|
132
|
+
this.logger.debug('Rejestrowanie wywołania RPC przez shared subscriber', {
|
|
133
|
+
processInstanceId: this.processInstanceId,
|
|
103
134
|
correlationId,
|
|
104
135
|
responseChannel,
|
|
105
136
|
commandName,
|
|
106
137
|
timeout: `${timeout}ms`,
|
|
107
138
|
timestamp: new Date().toISOString(),
|
|
108
139
|
});
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
if (channel !== responseChannel)
|
|
114
|
-
return;
|
|
115
|
-
try {
|
|
116
|
-
const { correlationId: responseCorrelationId, result, error } = JSON.parse(message);
|
|
117
|
-
this.logger.debug('Otrzymano odpowiedź RPC przez Pub/Sub', {
|
|
118
|
-
correlationId: responseCorrelationId,
|
|
119
|
-
hasResult: result !== undefined,
|
|
120
|
-
hasError: error !== undefined,
|
|
121
|
-
timestamp: new Date().toISOString(),
|
|
122
|
-
});
|
|
123
|
-
// Usunięcie handlera po otrzymaniu odpowiedzi
|
|
124
|
-
subscriber.off('message', messageHandler);
|
|
125
|
-
if (error) {
|
|
126
|
-
this.logger.error('Wywołanie RPC odrzucone', {
|
|
127
|
-
correlationId: responseCorrelationId,
|
|
128
|
-
error,
|
|
129
|
-
timestamp: new Date().toISOString(),
|
|
130
|
-
});
|
|
131
|
-
reject(new Error(error));
|
|
132
|
-
}
|
|
133
|
-
else {
|
|
134
|
-
this.logger.debug('Wywołanie RPC rozwiązane', {
|
|
135
|
-
correlationId: responseCorrelationId,
|
|
136
|
-
timestamp: new Date().toISOString(),
|
|
137
|
-
});
|
|
138
|
-
resolve(result);
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
catch (parseError) {
|
|
142
|
-
this.logger.error('Błąd parsowania odpowiedzi RPC', {
|
|
143
|
-
correlationId,
|
|
144
|
-
error: parseError instanceof Error ? parseError.message : String(parseError),
|
|
145
|
-
timestamp: new Date().toISOString(),
|
|
146
|
-
});
|
|
147
|
-
reject(new Error('Failed to parse RPC response'));
|
|
148
|
-
}
|
|
149
|
-
};
|
|
150
|
-
// Obsługa błędów Redis
|
|
151
|
-
const errorHandler = (error) => {
|
|
152
|
-
this.logger.error('Błąd Redis subscriber podczas RPC', {
|
|
153
|
-
correlationId,
|
|
154
|
-
error: error.message,
|
|
155
|
-
timestamp: new Date().toISOString(),
|
|
156
|
-
});
|
|
157
|
-
subscriber.off('message', messageHandler);
|
|
158
|
-
subscriber.off('error', errorHandler);
|
|
159
|
-
reject(new Error(`Redis subscriber error: ${error.message}`));
|
|
160
|
-
};
|
|
161
|
-
subscriber.on('message', messageHandler);
|
|
162
|
-
subscriber.on('error', errorHandler);
|
|
163
|
-
});
|
|
164
|
-
// Subskrybuj kanał PRZED wysłaniem komendy (zapobiega race condition)
|
|
165
|
-
yield subscriber.subscribe(responseChannel);
|
|
166
|
-
this.logger.debug('Subskrybowano kanał RPC', {
|
|
140
|
+
// Czekaj aż subscriber będzie gotowy (tylko przy pierwszym call)
|
|
141
|
+
if (!this.isSubscriberReady) {
|
|
142
|
+
this.logger.debug('Oczekiwanie na gotowość shared subscriber', {
|
|
143
|
+
processInstanceId: this.processInstanceId,
|
|
167
144
|
correlationId,
|
|
168
|
-
responseChannel,
|
|
169
145
|
timestamp: new Date().toISOString(),
|
|
170
146
|
});
|
|
171
|
-
|
|
172
|
-
const timeoutPromise = new Promise((_, reject) => {
|
|
173
|
-
timeoutId = setTimeout(() => {
|
|
174
|
-
this.logger.error('RPC timeout', {
|
|
175
|
-
commandName,
|
|
176
|
-
commandId: correlationId,
|
|
177
|
-
timeout: `${timeout}ms`,
|
|
178
|
-
timestamp: new Date().toISOString(),
|
|
179
|
-
});
|
|
180
|
-
reject(new Error(`RPC timeout for command ${commandName}`));
|
|
181
|
-
}, timeout);
|
|
182
|
-
});
|
|
183
|
-
// Czekaj na odpowiedź lub timeout (co nastąpi pierwsze)
|
|
184
|
-
return yield Promise.race([responsePromise, timeoutPromise]);
|
|
147
|
+
yield this.subscriberReadyPromise;
|
|
185
148
|
}
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
149
|
+
// Utwórz promise i dodaj do pending calls
|
|
150
|
+
return new Promise((resolve, reject) => {
|
|
151
|
+
const startTime = Date.now();
|
|
152
|
+
// Timeout handler
|
|
153
|
+
const timeoutId = setTimeout(() => {
|
|
154
|
+
this.pendingCalls.delete(correlationId);
|
|
155
|
+
this.logger.error('RPC timeout', {
|
|
156
|
+
processInstanceId: this.processInstanceId,
|
|
157
|
+
commandName,
|
|
194
158
|
correlationId,
|
|
195
|
-
|
|
159
|
+
responseChannel,
|
|
160
|
+
timeout: `${timeout}ms`,
|
|
161
|
+
pendingCallsCount: this.pendingCalls.size,
|
|
196
162
|
timestamp: new Date().toISOString(),
|
|
197
163
|
});
|
|
164
|
+
reject(new Error(`RPC timeout for command ${commandName}`));
|
|
165
|
+
}, timeout);
|
|
166
|
+
// Zapisz pending call w Map
|
|
167
|
+
this.pendingCalls.set(correlationId, {
|
|
168
|
+
resolve: resolve,
|
|
169
|
+
reject,
|
|
170
|
+
timeoutId,
|
|
171
|
+
commandName,
|
|
172
|
+
startTime,
|
|
198
173
|
});
|
|
199
|
-
|
|
174
|
+
this.logger.debug('Pending RPC call zarejestrowany', {
|
|
175
|
+
processInstanceId: this.processInstanceId,
|
|
176
|
+
correlationId,
|
|
177
|
+
responseChannel,
|
|
178
|
+
pendingCallsCount: this.pendingCalls.size,
|
|
179
|
+
timestamp: new Date().toISOString(),
|
|
180
|
+
});
|
|
181
|
+
});
|
|
200
182
|
});
|
|
201
183
|
}
|
|
202
184
|
/**
|
|
203
|
-
*
|
|
204
|
-
*
|
|
205
|
-
* Fail-safe - nie rzuca błędów, tylko loguje
|
|
185
|
+
* Obsługuje wiadomość RPC z Redis Pub/Sub (pmessage handler)
|
|
186
|
+
* Ekstraktuje correlationId, znajduje pending call, dekompresuje i resolve/reject
|
|
206
187
|
*
|
|
207
|
-
* @param
|
|
208
|
-
* @param
|
|
209
|
-
* @param correlationId - ID wywołania (dla logowania)
|
|
188
|
+
* @param channel - Pełna nazwa kanału: rpc:response:{processId}:{correlationId}
|
|
189
|
+
* @param message - Skompresowana odpowiedź RPC (JSON)
|
|
210
190
|
*/
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
191
|
+
handleRpcMessage(channel, message) {
|
|
192
|
+
// Ekstraktuj correlationId z channel: rpc:response:{processId}:{correlationId}
|
|
193
|
+
const parts = channel.split(':');
|
|
194
|
+
if (parts.length !== 4 || parts[0] !== 'rpc' || parts[1] !== 'response') {
|
|
195
|
+
this.logger.warn('Nieprawidłowy format kanału RPC', {
|
|
196
|
+
processInstanceId: this.processInstanceId,
|
|
197
|
+
channel,
|
|
198
|
+
timestamp: new Date().toISOString(),
|
|
199
|
+
});
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
const receivedProcessId = parts[2];
|
|
203
|
+
const correlationId = parts[3];
|
|
204
|
+
// Weryfikacja processInstanceId (dodatkowe bezpieczeństwo)
|
|
205
|
+
if (receivedProcessId !== this.processInstanceId) {
|
|
206
|
+
this.logger.warn('Otrzymano wiadomość dla innego procesu', {
|
|
207
|
+
processInstanceId: this.processInstanceId,
|
|
208
|
+
receivedProcessId,
|
|
214
209
|
correlationId,
|
|
215
|
-
|
|
210
|
+
channel,
|
|
216
211
|
timestamp: new Date().toISOString(),
|
|
217
212
|
});
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
this.
|
|
228
|
-
|
|
229
|
-
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
// Znajdź pending call w Map
|
|
216
|
+
const pendingCall = this.pendingCalls.get(correlationId);
|
|
217
|
+
if (!pendingCall) {
|
|
218
|
+
this.logger.warn('Otrzymano odpowiedź dla nieistniejącego RPC call', {
|
|
219
|
+
processInstanceId: this.processInstanceId,
|
|
220
|
+
correlationId,
|
|
221
|
+
channel,
|
|
222
|
+
pendingCallsCount: this.pendingCalls.size,
|
|
223
|
+
timestamp: new Date().toISOString(),
|
|
224
|
+
});
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
227
|
+
// Dekompresuj i parsuj odpowiedź (async)
|
|
228
|
+
// Message zawiera wrapper: {data: string, compressed: boolean}
|
|
229
|
+
let wrapper;
|
|
230
|
+
try {
|
|
231
|
+
wrapper = JSON.parse(message);
|
|
232
|
+
}
|
|
233
|
+
catch (parseError) {
|
|
234
|
+
this.logger.error('Błąd parsowania wrapper odpowiedzi RPC', {
|
|
235
|
+
processInstanceId: this.processInstanceId,
|
|
236
|
+
correlationId,
|
|
237
|
+
commandName: pendingCall.commandName,
|
|
238
|
+
error: parseError instanceof Error ? parseError.message : String(parseError),
|
|
239
|
+
timestamp: new Date().toISOString(),
|
|
240
|
+
});
|
|
241
|
+
clearTimeout(pendingCall.timeoutId);
|
|
242
|
+
this.pendingCalls.delete(correlationId);
|
|
243
|
+
pendingCall.reject(new Error('Failed to parse RPC response wrapper'));
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
this.compressionService
|
|
247
|
+
.decompress(wrapper.data, wrapper.compressed)
|
|
248
|
+
.then((decompressed) => {
|
|
249
|
+
const { correlationId: responseCorrelationId, result, error, } = decompressed;
|
|
250
|
+
const duration = Date.now() - pendingCall.startTime;
|
|
251
|
+
this.logger.debug('Otrzymano odpowiedź RPC przez shared subscriber', {
|
|
252
|
+
processInstanceId: this.processInstanceId,
|
|
253
|
+
correlationId: responseCorrelationId,
|
|
254
|
+
commandName: pendingCall.commandName,
|
|
255
|
+
duration: `${duration}ms`,
|
|
256
|
+
hasResult: result !== undefined,
|
|
257
|
+
hasError: error !== undefined,
|
|
258
|
+
pendingCallsCount: this.pendingCalls.size - 1,
|
|
259
|
+
timestamp: new Date().toISOString(),
|
|
260
|
+
});
|
|
261
|
+
// Cleanup
|
|
262
|
+
clearTimeout(pendingCall.timeoutId);
|
|
263
|
+
this.pendingCalls.delete(correlationId);
|
|
264
|
+
// Resolve/reject promise
|
|
265
|
+
if (error) {
|
|
266
|
+
this.logger.error('Wywołanie RPC odrzucone', {
|
|
267
|
+
processInstanceId: this.processInstanceId,
|
|
268
|
+
correlationId: responseCorrelationId,
|
|
269
|
+
commandName: pendingCall.commandName,
|
|
270
|
+
error,
|
|
230
271
|
timestamp: new Date().toISOString(),
|
|
231
272
|
});
|
|
273
|
+
pendingCall.reject(new Error(error));
|
|
232
274
|
}
|
|
233
|
-
|
|
234
|
-
this.logger.
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
275
|
+
else {
|
|
276
|
+
this.logger.debug('Wywołanie RPC rozwiązane', {
|
|
277
|
+
processInstanceId: this.processInstanceId,
|
|
278
|
+
correlationId: responseCorrelationId,
|
|
279
|
+
commandName: pendingCall.commandName,
|
|
280
|
+
duration: `${duration}ms`,
|
|
238
281
|
timestamp: new Date().toISOString(),
|
|
239
282
|
});
|
|
283
|
+
pendingCall.resolve(result);
|
|
240
284
|
}
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
285
|
+
})
|
|
286
|
+
.catch((decompressError) => {
|
|
287
|
+
this.logger.error('Błąd dekompresji/parsowania odpowiedzi RPC', {
|
|
288
|
+
processInstanceId: this.processInstanceId,
|
|
289
|
+
correlationId,
|
|
290
|
+
commandName: pendingCall.commandName,
|
|
291
|
+
error: decompressError instanceof Error ? decompressError.message : String(decompressError),
|
|
292
|
+
timestamp: new Date().toISOString(),
|
|
293
|
+
});
|
|
294
|
+
// Cleanup
|
|
295
|
+
clearTimeout(pendingCall.timeoutId);
|
|
296
|
+
this.pendingCalls.delete(correlationId);
|
|
297
|
+
pendingCall.reject(new Error('Failed to decompress/parse RPC response'));
|
|
246
298
|
});
|
|
247
299
|
}
|
|
248
300
|
/**
|
|
249
|
-
* Zamyka
|
|
250
|
-
*
|
|
301
|
+
* Zamyka RpcCoordinator i czyści zasoby
|
|
302
|
+
* Reject wszystkie pending calls i zamknij shared subscriber
|
|
251
303
|
*/
|
|
252
304
|
close() {
|
|
253
305
|
return __awaiter(this, void 0, void 0, function* () {
|
|
254
|
-
this.logger.debug('Zamykanie
|
|
255
|
-
|
|
306
|
+
this.logger.debug('Zamykanie RpcCoordinator', {
|
|
307
|
+
processInstanceId: this.processInstanceId,
|
|
308
|
+
pendingCallsCount: this.pendingCalls.size,
|
|
256
309
|
timestamp: new Date().toISOString(),
|
|
257
310
|
});
|
|
258
|
-
//
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
311
|
+
// Reject wszystkie pending calls
|
|
312
|
+
for (const [correlationId, pendingCall] of this.pendingCalls.entries()) {
|
|
313
|
+
clearTimeout(pendingCall.timeoutId);
|
|
314
|
+
pendingCall.reject(new Error('RpcCoordinator is closing'));
|
|
315
|
+
this.logger.debug('Odrzucono pending RPC call przy zamykaniu', {
|
|
316
|
+
processInstanceId: this.processInstanceId,
|
|
317
|
+
correlationId,
|
|
318
|
+
commandName: pendingCall.commandName,
|
|
319
|
+
timestamp: new Date().toISOString(),
|
|
320
|
+
});
|
|
321
|
+
}
|
|
322
|
+
this.pendingCalls.clear();
|
|
323
|
+
// Zamknij shared subscriber
|
|
324
|
+
try {
|
|
325
|
+
const pattern = `rpc:response:${this.processInstanceId}:*`;
|
|
326
|
+
yield this.sharedSubscriber.punsubscribe(pattern);
|
|
327
|
+
this.sharedSubscriber.removeAllListeners('pmessage');
|
|
328
|
+
this.sharedSubscriber.removeAllListeners('psubscribe');
|
|
329
|
+
this.sharedSubscriber.removeAllListeners('error');
|
|
330
|
+
yield this.sharedSubscriber.quit();
|
|
331
|
+
this.logger.debug('Shared subscriber zamknięty', {
|
|
332
|
+
processInstanceId: this.processInstanceId,
|
|
262
333
|
timestamp: new Date().toISOString(),
|
|
263
334
|
});
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
335
|
+
}
|
|
336
|
+
catch (error) {
|
|
337
|
+
this.logger.warn('Błąd podczas zamykania shared subscriber', {
|
|
338
|
+
processInstanceId: this.processInstanceId,
|
|
339
|
+
error: error instanceof Error ? error.message : String(error),
|
|
340
|
+
timestamp: new Date().toISOString(),
|
|
341
|
+
});
|
|
342
|
+
}
|
|
343
|
+
this.logger.debug('RpcCoordinator zamknięty', {
|
|
344
|
+
processInstanceId: this.processInstanceId,
|
|
268
345
|
timestamp: new Date().toISOString(),
|
|
269
346
|
});
|
|
270
347
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rpc-coordinator.js","sourceRoot":"","sources":["../../../src/command-bus/rpc/rpc-coordinator.ts"],"names":[],"mappings":";;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"rpc-coordinator.js","sourceRoot":"","sources":["../../../src/command-bus/rpc/rpc-coordinator.ts"],"names":[],"mappings":"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"}
|