pp-command-bus 1.5.0 → 2.0.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.
- package/README.md +400 -1219
- package/dist/command-bus/command-bus.spec.js +138 -359
- package/dist/command-bus/command-bus.spec.js.map +1 -1
- package/dist/command-bus/command.d.ts +3 -4
- package/dist/command-bus/command.js +3 -32
- package/dist/command-bus/command.js.map +1 -1
- package/dist/command-bus/config/command-bus-config.d.ts +80 -21
- package/dist/command-bus/config/command-bus-config.js +104 -58
- package/dist/command-bus/config/command-bus-config.js.map +1 -1
- package/dist/command-bus/config/command-bus-config.spec.js +174 -100
- package/dist/command-bus/config/command-bus-config.spec.js.map +1 -1
- package/dist/command-bus/index.d.ts +41 -50
- package/dist/command-bus/index.js +143 -127
- package/dist/command-bus/index.js.map +1 -1
- package/dist/command-bus/interceptors/index.d.ts +5 -0
- package/dist/command-bus/interceptors/index.js +22 -0
- package/dist/command-bus/interceptors/index.js.map +1 -0
- package/dist/command-bus/interceptors/interceptor.interface.d.ts +35 -0
- package/dist/command-bus/interceptors/interceptor.interface.js +3 -0
- package/dist/command-bus/interceptors/interceptor.interface.js.map +1 -0
- package/dist/command-bus/interceptors/performance-interceptor.d.ts +24 -0
- package/dist/command-bus/interceptors/performance-interceptor.js +86 -0
- package/dist/command-bus/interceptors/performance-interceptor.js.map +1 -0
- package/dist/command-bus/interceptors/performance-interceptor.spec.js +124 -0
- package/dist/command-bus/interceptors/performance-interceptor.spec.js.map +1 -0
- package/dist/command-bus/logging/command-logger.d.ts +2 -0
- package/dist/command-bus/logging/command-logger.js +7 -0
- package/dist/command-bus/logging/command-logger.js.map +1 -1
- package/dist/command-bus/logging/command-logger.spec.js +36 -0
- package/dist/command-bus/logging/command-logger.spec.js.map +1 -1
- package/dist/command-bus/serialization/index.d.ts +6 -0
- package/dist/command-bus/serialization/index.js +9 -0
- package/dist/command-bus/serialization/index.js.map +1 -0
- package/dist/command-bus/serialization/msgpack-serializer.d.ts +26 -0
- package/dist/command-bus/serialization/msgpack-serializer.js +70 -0
- package/dist/command-bus/serialization/msgpack-serializer.js.map +1 -0
- package/dist/command-bus/serialization/msgpack-serializer.spec.js +223 -0
- package/dist/command-bus/serialization/msgpack-serializer.spec.js.map +1 -0
- package/dist/command-bus/serialization/serializer.interface.d.ts +21 -0
- package/dist/command-bus/serialization/serializer.interface.js +3 -0
- package/dist/command-bus/serialization/serializer.interface.js.map +1 -0
- package/dist/command-bus/transport/consumer-loop.d.ts +45 -0
- package/dist/command-bus/transport/consumer-loop.js +90 -0
- package/dist/command-bus/transport/consumer-loop.js.map +1 -0
- package/dist/command-bus/transport/consumer-loop.spec.js +216 -0
- package/dist/command-bus/transport/consumer-loop.spec.js.map +1 -0
- package/dist/command-bus/transport/index.d.ts +21 -0
- package/dist/command-bus/transport/index.js +23 -0
- package/dist/command-bus/transport/index.js.map +1 -0
- package/dist/command-bus/transport/message-processor.d.ts +70 -0
- package/dist/command-bus/transport/message-processor.js +158 -0
- package/dist/command-bus/transport/message-processor.js.map +1 -0
- package/dist/command-bus/transport/message-processor.spec.js +185 -0
- package/dist/command-bus/transport/message-processor.spec.js.map +1 -0
- package/dist/command-bus/transport/pending-recovery.d.ts +54 -0
- package/dist/command-bus/transport/pending-recovery.js +139 -0
- package/dist/command-bus/transport/pending-recovery.js.map +1 -0
- package/dist/command-bus/transport/pending-recovery.spec.js +176 -0
- package/dist/command-bus/transport/pending-recovery.spec.js.map +1 -0
- package/dist/command-bus/transport/redis-codec.d.ts +24 -0
- package/dist/command-bus/transport/redis-codec.js +33 -0
- package/dist/command-bus/transport/redis-codec.js.map +1 -0
- package/dist/command-bus/transport/redis-codec.spec.js +53 -0
- package/dist/command-bus/transport/redis-codec.spec.js.map +1 -0
- package/dist/command-bus/transport/redis-streams-transport.d.ts +94 -0
- package/dist/command-bus/transport/redis-streams-transport.js +143 -0
- package/dist/command-bus/transport/redis-streams-transport.js.map +1 -0
- package/dist/command-bus/transport/redis-streams-transport.spec.js +420 -0
- package/dist/command-bus/transport/redis-streams-transport.spec.js.map +1 -0
- package/dist/command-bus/transport/rpc-handler.d.ts +39 -0
- package/dist/command-bus/transport/rpc-handler.js +87 -0
- package/dist/command-bus/transport/rpc-handler.js.map +1 -0
- package/dist/command-bus/transport/rpc-handler.spec.js +157 -0
- package/dist/command-bus/transport/rpc-handler.spec.js.map +1 -0
- package/dist/command-bus/transport/stream-consumer.d.ts +91 -0
- package/dist/command-bus/transport/stream-consumer.js +182 -0
- package/dist/command-bus/transport/stream-consumer.js.map +1 -0
- package/dist/command-bus/transport/stream-consumer.spec.js +284 -0
- package/dist/command-bus/transport/stream-consumer.spec.js.map +1 -0
- package/dist/command-bus/transport/stream-producer.d.ts +23 -0
- package/dist/command-bus/transport/stream-producer.js +70 -0
- package/dist/command-bus/transport/stream-producer.js.map +1 -0
- package/dist/command-bus/transport/stream-producer.spec.js +125 -0
- package/dist/command-bus/transport/stream-producer.spec.js.map +1 -0
- package/dist/command-bus/transport/transport.interface.d.ts +87 -0
- package/dist/command-bus/transport/transport.interface.js +3 -0
- package/dist/command-bus/transport/transport.interface.js.map +1 -0
- package/dist/command-bus/types/index.d.ts +0 -84
- package/dist/examples/rpc.demo.js +1 -1
- package/dist/examples/rpc.demo.js.map +1 -1
- package/dist/index.d.ts +8 -5
- package/dist/index.js +6 -4
- package/dist/index.js.map +1 -1
- package/dist/pp-command-bus-2.0.1.tgz +0 -0
- package/dist/shared/redis/connection-pool.d.ts +54 -0
- package/dist/shared/redis/connection-pool.js +123 -0
- package/dist/shared/redis/connection-pool.js.map +1 -0
- package/dist/shared/redis/connection-pool.spec.d.ts +1 -0
- package/dist/shared/redis/connection-pool.spec.js +114 -0
- package/dist/shared/redis/connection-pool.spec.js.map +1 -0
- package/dist/shared/redis/index.d.ts +5 -3
- package/dist/shared/redis/index.js +6 -4
- package/dist/shared/redis/index.js.map +1 -1
- package/dist/shared/redis/rpc-connection-pool.d.ts +61 -0
- package/dist/shared/redis/rpc-connection-pool.js +154 -0
- package/dist/shared/redis/rpc-connection-pool.js.map +1 -0
- package/dist/shared/redis/rpc-connection-pool.spec.d.ts +1 -0
- package/dist/shared/redis/rpc-connection-pool.spec.js +173 -0
- package/dist/shared/redis/rpc-connection-pool.spec.js.map +1 -0
- package/dist/shared/types.d.ts +0 -4
- package/dist/shared/utils/error-utils.d.ts +8 -0
- package/dist/shared/utils/error-utils.js +14 -0
- package/dist/shared/utils/error-utils.js.map +1 -0
- package/package.json +12 -12
- package/dist/command-bus/config/auto-config-optimizer.d.ts +0 -35
- package/dist/command-bus/config/auto-config-optimizer.js +0 -52
- package/dist/command-bus/config/auto-config-optimizer.js.map +0 -1
- package/dist/command-bus/config/auto-config-optimizer.spec.js +0 -42
- package/dist/command-bus/config/auto-config-optimizer.spec.js.map +0 -1
- package/dist/command-bus/job/index.d.ts +0 -6
- package/dist/command-bus/job/index.js +0 -15
- package/dist/command-bus/job/index.js.map +0 -1
- package/dist/command-bus/job/job-options-builder.d.ts +0 -21
- package/dist/command-bus/job/job-options-builder.js +0 -58
- package/dist/command-bus/job/job-options-builder.js.map +0 -1
- package/dist/command-bus/job/job-options-builder.spec.js +0 -156
- package/dist/command-bus/job/job-options-builder.spec.js.map +0 -1
- package/dist/command-bus/job/job-processor.d.ts +0 -39
- package/dist/command-bus/job/job-processor.js +0 -203
- package/dist/command-bus/job/job-processor.js.map +0 -1
- package/dist/command-bus/job/job-processor.spec.js +0 -436
- package/dist/command-bus/job/job-processor.spec.js.map +0 -1
- package/dist/command-bus/queue/index.d.ts +0 -5
- package/dist/command-bus/queue/index.js +0 -13
- package/dist/command-bus/queue/index.js.map +0 -1
- package/dist/command-bus/queue/queue-manager.d.ts +0 -56
- package/dist/command-bus/queue/queue-manager.js +0 -163
- package/dist/command-bus/queue/queue-manager.js.map +0 -1
- package/dist/command-bus/queue/queue-manager.spec.js +0 -371
- package/dist/command-bus/queue/queue-manager.spec.js.map +0 -1
- package/dist/command-bus/rpc/index.d.ts +0 -11
- package/dist/command-bus/rpc/index.js +0 -19
- package/dist/command-bus/rpc/index.js.map +0 -1
- package/dist/command-bus/rpc/payload-compression.service.d.ts +0 -50
- package/dist/command-bus/rpc/payload-compression.service.js +0 -215
- package/dist/command-bus/rpc/payload-compression.service.js.map +0 -1
- package/dist/command-bus/rpc/payload-compression.service.spec.js +0 -376
- package/dist/command-bus/rpc/payload-compression.service.spec.js.map +0 -1
- package/dist/command-bus/rpc/rpc-coordinator.d.ts +0 -96
- package/dist/command-bus/rpc/rpc-coordinator.js +0 -500
- package/dist/command-bus/rpc/rpc-coordinator.js.map +0 -1
- package/dist/command-bus/rpc/rpc-coordinator.spec.js +0 -621
- package/dist/command-bus/rpc/rpc-coordinator.spec.js.map +0 -1
- package/dist/command-bus/rpc/rpc-job-cancellation.service.d.ts +0 -82
- package/dist/command-bus/rpc/rpc-job-cancellation.service.js +0 -180
- package/dist/command-bus/rpc/rpc-job-cancellation.service.js.map +0 -1
- package/dist/command-bus/rpc/rpc-job-cancellation.service.spec.js +0 -286
- package/dist/command-bus/rpc/rpc-job-cancellation.service.spec.js.map +0 -1
- package/dist/command-bus/worker/index.d.ts +0 -10
- package/dist/command-bus/worker/index.js +0 -19
- package/dist/command-bus/worker/index.js.map +0 -1
- package/dist/command-bus/worker/worker-benchmark.d.ts +0 -71
- package/dist/command-bus/worker/worker-benchmark.js +0 -202
- package/dist/command-bus/worker/worker-benchmark.js.map +0 -1
- package/dist/command-bus/worker/worker-benchmark.spec.js +0 -310
- package/dist/command-bus/worker/worker-benchmark.spec.js.map +0 -1
- package/dist/command-bus/worker/worker-metrics-collector.d.ts +0 -98
- package/dist/command-bus/worker/worker-metrics-collector.js +0 -242
- package/dist/command-bus/worker/worker-metrics-collector.js.map +0 -1
- package/dist/command-bus/worker/worker-orchestrator.d.ts +0 -70
- package/dist/command-bus/worker/worker-orchestrator.js +0 -339
- package/dist/command-bus/worker/worker-orchestrator.js.map +0 -1
- package/dist/command-bus/worker/worker-orchestrator.spec.js +0 -712
- package/dist/command-bus/worker/worker-orchestrator.spec.js.map +0 -1
- package/dist/examples/auto-config.demo.d.ts +0 -9
- package/dist/examples/auto-config.demo.js +0 -106
- package/dist/examples/auto-config.demo.js.map +0 -1
- package/dist/examples/rpc-compression.demo.d.ts +0 -5
- package/dist/examples/rpc-compression.demo.js +0 -358
- package/dist/examples/rpc-compression.demo.js.map +0 -1
- package/dist/examples/rpc-resilience.demo.d.ts +0 -15
- package/dist/examples/rpc-resilience.demo.js +0 -233
- package/dist/examples/rpc-resilience.demo.js.map +0 -1
- package/dist/pp-command-bus-1.5.0.tgz +0 -0
- package/dist/shared/config/base-config.d.ts +0 -54
- package/dist/shared/config/base-config.js +0 -114
- package/dist/shared/config/base-config.js.map +0 -1
- package/dist/shared/config/base-config.spec.js +0 -204
- package/dist/shared/config/base-config.spec.js.map +0 -1
- package/dist/shared/config/index.d.ts +0 -1
- package/dist/shared/config/index.js +0 -9
- package/dist/shared/config/index.js.map +0 -1
- package/dist/shared/redis/redis-connection-factory.d.ts +0 -66
- package/dist/shared/redis/redis-connection-factory.js +0 -113
- package/dist/shared/redis/redis-connection-factory.js.map +0 -1
- /package/dist/command-bus/{config/auto-config-optimizer.spec.d.ts → interceptors/performance-interceptor.spec.d.ts} +0 -0
- /package/dist/command-bus/{job/job-options-builder.spec.d.ts → serialization/msgpack-serializer.spec.d.ts} +0 -0
- /package/dist/command-bus/{job/job-processor.spec.d.ts → transport/consumer-loop.spec.d.ts} +0 -0
- /package/dist/command-bus/{queue/queue-manager.spec.d.ts → transport/message-processor.spec.d.ts} +0 -0
- /package/dist/command-bus/{rpc/payload-compression.service.spec.d.ts → transport/pending-recovery.spec.d.ts} +0 -0
- /package/dist/command-bus/{rpc/rpc-coordinator.spec.d.ts → transport/redis-codec.spec.d.ts} +0 -0
- /package/dist/command-bus/{rpc/rpc-job-cancellation.service.spec.d.ts → transport/redis-streams-transport.spec.d.ts} +0 -0
- /package/dist/command-bus/{worker/worker-benchmark.spec.d.ts → transport/rpc-handler.spec.d.ts} +0 -0
- /package/dist/command-bus/{worker/worker-orchestrator.spec.d.ts → transport/stream-consumer.spec.d.ts} +0 -0
- /package/dist/{shared/config/base-config.spec.d.ts → command-bus/transport/stream-producer.spec.d.ts} +0 -0
|
@@ -0,0 +1,158 @@
|
|
|
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
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.MessageProcessor = void 0;
|
|
13
|
+
const redis_codec_1 = require("./redis-codec");
|
|
14
|
+
/**
|
|
15
|
+
* Procesor wiadomości — parsuje, waliduje, przetwarza i potwierdza wiadomości
|
|
16
|
+
*
|
|
17
|
+
* Odpowiedzialności:
|
|
18
|
+
* - Parsowanie fields → fieldMap
|
|
19
|
+
* - Walidacja danych wejściowych (H4)
|
|
20
|
+
* - Detekcja RPC via marker field
|
|
21
|
+
* - Wywołanie handlera
|
|
22
|
+
* - XACK + throttled XTRIM (H2: per-stream counters)
|
|
23
|
+
* - Wysyłanie odpowiedzi RPC
|
|
24
|
+
*
|
|
25
|
+
* NIE odpowiada za deduplicację — to odpowiedzialność koordynatora (StreamConsumer)
|
|
26
|
+
*/
|
|
27
|
+
class MessageProcessor {
|
|
28
|
+
constructor(options) {
|
|
29
|
+
/** H2: Liczniki wiadomości od ostatniego XTRIM — per strumień */
|
|
30
|
+
this.xtrimCounters = new Map();
|
|
31
|
+
this.pool = options.pool;
|
|
32
|
+
this.serializer = options.serializer;
|
|
33
|
+
this.logger = options.logger;
|
|
34
|
+
this.batchSize = options.batchSize;
|
|
35
|
+
this.maxRetained = options.maxRetained;
|
|
36
|
+
this.rpcRespond = options.rpcRespond;
|
|
37
|
+
this.interceptor = options.interceptor;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Czyści stan counters — wywoływane przy close()
|
|
41
|
+
*/
|
|
42
|
+
reset() {
|
|
43
|
+
this.xtrimCounters.clear();
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Przetwarza wiadomość — parsuje fields, wykrywa RPC, wywołuje handler, XACK/XTRIM
|
|
47
|
+
*
|
|
48
|
+
* Błędy propagują do callera (koordynatora) — nie łapie wewnętrznie
|
|
49
|
+
*
|
|
50
|
+
* @param streamName - Nazwa strumienia Redis
|
|
51
|
+
* @param groupName - Nazwa grupy konsumentów
|
|
52
|
+
* @param messageId - ID wiadomości
|
|
53
|
+
* @param fields - Tablica pól ze strumienia [key, value, key, value, ...]
|
|
54
|
+
* @param handler - Handler przetwarzający dane komendy
|
|
55
|
+
*/
|
|
56
|
+
process(streamName, groupName, messageId, fields, handler) {
|
|
57
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
58
|
+
var _a;
|
|
59
|
+
// H4: Walidacja fields array — zapobiega crash na pustych/nieparzystych danych
|
|
60
|
+
if (!fields || fields.length < 2) {
|
|
61
|
+
this.logger.warn('Nieprawidłowa wiadomość — brak danych', { streamName, messageId });
|
|
62
|
+
yield this.pool.next().xack(streamName, groupName, messageId);
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
const fieldMap = new Map();
|
|
66
|
+
for (let i = 0; i < fields.length; i += 2) {
|
|
67
|
+
if (i + 1 < fields.length) {
|
|
68
|
+
fieldMap.set(fields[i], fields[i + 1]);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
const rawData = fieldMap.get('data');
|
|
72
|
+
// H4: Walidacja rawData przed decode
|
|
73
|
+
if (rawData === undefined || rawData === null) {
|
|
74
|
+
this.logger.warn('Wiadomość bez pola data', { streamName, messageId });
|
|
75
|
+
yield this.pool.next().xack(streamName, groupName, messageId);
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
const dataBuffer = redis_codec_1.RedisCodec.decode(rawData);
|
|
79
|
+
let commandData;
|
|
80
|
+
let rpcMetadata;
|
|
81
|
+
if (fieldMap.has('rpc')) {
|
|
82
|
+
const envelope = this.serializer.deserialize(dataBuffer);
|
|
83
|
+
commandData = redis_codec_1.RedisCodec.decode(envelope.commandData);
|
|
84
|
+
rpcMetadata = envelope.rpc;
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
commandData = dataBuffer;
|
|
88
|
+
}
|
|
89
|
+
// Extract commandId from commandData for correlation
|
|
90
|
+
const commandId = this.extractCommandId(commandData);
|
|
91
|
+
let result;
|
|
92
|
+
if (this.interceptor) {
|
|
93
|
+
// Wykonaj przez interceptor
|
|
94
|
+
const execResult = yield this.interceptor.intercept({
|
|
95
|
+
commandId,
|
|
96
|
+
commandName: this.extractCommandName(streamName),
|
|
97
|
+
streamName,
|
|
98
|
+
messageId,
|
|
99
|
+
timestamp: Date.now(),
|
|
100
|
+
}, handler, commandData);
|
|
101
|
+
if (!execResult.success && execResult.error) {
|
|
102
|
+
throw execResult.error;
|
|
103
|
+
}
|
|
104
|
+
result = execResult.result;
|
|
105
|
+
}
|
|
106
|
+
else {
|
|
107
|
+
// Wykonaj bezpośrednio (backwards compatible)
|
|
108
|
+
result = yield handler(commandData);
|
|
109
|
+
}
|
|
110
|
+
// Log success
|
|
111
|
+
this.logger.log('Komenda przetworzona', {
|
|
112
|
+
streamName,
|
|
113
|
+
messageId,
|
|
114
|
+
commandId,
|
|
115
|
+
timestamp: new Date().toISOString(),
|
|
116
|
+
});
|
|
117
|
+
// H2: XACK + throttled XTRIM per strumień
|
|
118
|
+
const count = ((_a = this.xtrimCounters.get(streamName)) !== null && _a !== void 0 ? _a : 0) + 1;
|
|
119
|
+
this.xtrimCounters.set(streamName, count);
|
|
120
|
+
const conn = this.pool.next();
|
|
121
|
+
if (count >= this.batchSize) {
|
|
122
|
+
const pipeline = conn.pipeline();
|
|
123
|
+
pipeline.xack(streamName, groupName, messageId);
|
|
124
|
+
pipeline.xtrim(streamName, 'MAXLEN', '~', this.maxRetained);
|
|
125
|
+
yield pipeline.exec();
|
|
126
|
+
this.xtrimCounters.set(streamName, 0);
|
|
127
|
+
}
|
|
128
|
+
else {
|
|
129
|
+
yield conn.xack(streamName, groupName, messageId);
|
|
130
|
+
}
|
|
131
|
+
if (rpcMetadata) {
|
|
132
|
+
const responseBuffer = this.serializer.serialize({ result, error: null });
|
|
133
|
+
yield this.rpcRespond(rpcMetadata.responseKey, responseBuffer, 60);
|
|
134
|
+
}
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Ekstrakcja commandId z commandData (deserializacja metadata)
|
|
139
|
+
*/
|
|
140
|
+
extractCommandId(data) {
|
|
141
|
+
var _a;
|
|
142
|
+
try {
|
|
143
|
+
const cmd = this.serializer.deserialize(data);
|
|
144
|
+
return (_a = cmd.__id) !== null && _a !== void 0 ? _a : 'unknown';
|
|
145
|
+
}
|
|
146
|
+
catch (_b) {
|
|
147
|
+
return 'unknown';
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Ekstrakcja nazwy komendy ze streamName (usunięcie prefiksu 'cmd:')
|
|
152
|
+
*/
|
|
153
|
+
extractCommandName(streamName) {
|
|
154
|
+
return streamName.replace('cmd:', '');
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
exports.MessageProcessor = MessageProcessor;
|
|
158
|
+
//# sourceMappingURL=message-processor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"message-processor.js","sourceRoot":"","sources":["../../../src/command-bus/transport/message-processor.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,185 @@
|
|
|
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
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
const message_processor_1 = require("./message-processor");
|
|
13
|
+
const redis_codec_1 = require("./redis-codec");
|
|
14
|
+
/**
|
|
15
|
+
* Mock helpers
|
|
16
|
+
*/
|
|
17
|
+
function createMockLogger() {
|
|
18
|
+
return {
|
|
19
|
+
log: jest.fn(),
|
|
20
|
+
error: jest.fn(),
|
|
21
|
+
warn: jest.fn(),
|
|
22
|
+
debug: jest.fn(),
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
function createMockSerializer() {
|
|
26
|
+
return {
|
|
27
|
+
serialize: jest.fn((data) => Buffer.from(JSON.stringify(data))),
|
|
28
|
+
deserialize: jest.fn((buf) => JSON.parse(buf.toString())),
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
function createMockConnection() {
|
|
32
|
+
return {
|
|
33
|
+
xack: jest.fn().mockResolvedValue(1),
|
|
34
|
+
pipeline: jest.fn().mockReturnValue({
|
|
35
|
+
xack: jest.fn().mockReturnThis(),
|
|
36
|
+
xtrim: jest.fn().mockReturnThis(),
|
|
37
|
+
exec: jest.fn().mockResolvedValue([
|
|
38
|
+
[null, 1],
|
|
39
|
+
[null, 0],
|
|
40
|
+
]),
|
|
41
|
+
}),
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
function createMockPool() {
|
|
45
|
+
const conn = createMockConnection();
|
|
46
|
+
return {
|
|
47
|
+
pool: { next: jest.fn().mockReturnValue(conn) },
|
|
48
|
+
conn,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
describe('MessageProcessor', () => {
|
|
52
|
+
let processor;
|
|
53
|
+
let logger;
|
|
54
|
+
let serializer;
|
|
55
|
+
let mockConn;
|
|
56
|
+
let mockPool;
|
|
57
|
+
const rpcRespond = jest.fn().mockResolvedValue(undefined);
|
|
58
|
+
beforeEach(() => {
|
|
59
|
+
jest.clearAllMocks();
|
|
60
|
+
logger = createMockLogger();
|
|
61
|
+
serializer = createMockSerializer();
|
|
62
|
+
const poolMock = createMockPool();
|
|
63
|
+
mockPool = poolMock.pool;
|
|
64
|
+
mockConn = poolMock.conn;
|
|
65
|
+
processor = new message_processor_1.MessageProcessor({
|
|
66
|
+
pool: mockPool,
|
|
67
|
+
serializer,
|
|
68
|
+
logger,
|
|
69
|
+
batchSize: 10,
|
|
70
|
+
maxRetained: 10000,
|
|
71
|
+
rpcRespond,
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
describe('process()', () => {
|
|
75
|
+
it('powinien przetworzyć wiadomość i wywołać handler', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
76
|
+
const handler = jest.fn().mockResolvedValue('ok');
|
|
77
|
+
const testPayload = redis_codec_1.RedisCodec.encode(Buffer.from('test-data'));
|
|
78
|
+
const fields = ['data', testPayload];
|
|
79
|
+
yield processor.process('cmd:Test', 'workers', 'msg-1', fields, handler);
|
|
80
|
+
expect(handler).toHaveBeenCalledTimes(1);
|
|
81
|
+
expect(handler).toHaveBeenCalledWith(expect.any(Buffer));
|
|
82
|
+
}));
|
|
83
|
+
it('powinien XACK wiadomość po przetworzeniu', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
84
|
+
const handler = jest.fn().mockResolvedValue('ok');
|
|
85
|
+
const fields = ['data', redis_codec_1.RedisCodec.encode(Buffer.from('data'))];
|
|
86
|
+
yield processor.process('cmd:Test', 'workers', 'msg-1', fields, handler);
|
|
87
|
+
expect(mockConn.xack).toHaveBeenCalledWith('cmd:Test', 'workers', 'msg-1');
|
|
88
|
+
}));
|
|
89
|
+
it('powinien odrzucić wiadomość z pustym fields array (H4)', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
90
|
+
const handler = jest.fn();
|
|
91
|
+
yield processor.process('cmd:Test', 'workers', 'msg-empty', [], handler);
|
|
92
|
+
expect(handler).not.toHaveBeenCalled();
|
|
93
|
+
expect(logger.warn).toHaveBeenCalledWith('Nieprawidłowa wiadomość — brak danych', expect.objectContaining({ messageId: 'msg-empty' }));
|
|
94
|
+
expect(mockConn.xack).toHaveBeenCalledWith('cmd:Test', 'workers', 'msg-empty');
|
|
95
|
+
}));
|
|
96
|
+
it('powinien odrzucić wiadomość z jednym elementem (H4)', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
97
|
+
const handler = jest.fn();
|
|
98
|
+
yield processor.process('cmd:Test', 'workers', 'msg-odd', ['key-only'], handler);
|
|
99
|
+
expect(handler).not.toHaveBeenCalled();
|
|
100
|
+
expect(logger.warn).toHaveBeenCalledWith('Nieprawidłowa wiadomość — brak danych', expect.objectContaining({ messageId: 'msg-odd' }));
|
|
101
|
+
}));
|
|
102
|
+
it('powinien odrzucić wiadomość bez pola data (H4)', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
103
|
+
const handler = jest.fn();
|
|
104
|
+
yield processor.process('cmd:Test', 'workers', 'msg-nodata', ['other', 'value'], handler);
|
|
105
|
+
expect(handler).not.toHaveBeenCalled();
|
|
106
|
+
expect(logger.warn).toHaveBeenCalledWith('Wiadomość bez pola data', expect.objectContaining({ messageId: 'msg-nodata' }));
|
|
107
|
+
}));
|
|
108
|
+
it('powinien obsłużyć nieparzystą liczbę elementów (H4)', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
109
|
+
const handler = jest.fn().mockResolvedValue('ok');
|
|
110
|
+
const fields = ['data', redis_codec_1.RedisCodec.encode(Buffer.from('data')), 'extra-key'];
|
|
111
|
+
yield processor.process('cmd:Test', 'workers', 'msg-odd-fields', fields, handler);
|
|
112
|
+
expect(handler).toHaveBeenCalledTimes(1);
|
|
113
|
+
}));
|
|
114
|
+
it('powinien propagować błąd handlera do callera', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
115
|
+
const handler = jest.fn().mockRejectedValue(new Error('Handler error'));
|
|
116
|
+
const fields = ['data', redis_codec_1.RedisCodec.encode(Buffer.from('data'))];
|
|
117
|
+
yield expect(processor.process('cmd:Test', 'workers', 'msg-err', fields, handler)).rejects.toThrow('Handler error');
|
|
118
|
+
}));
|
|
119
|
+
});
|
|
120
|
+
describe('RPC detection', () => {
|
|
121
|
+
it('powinien wykryć RPC wiadomość przez marker i odpowiedzieć', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
122
|
+
const handler = jest.fn().mockResolvedValue('result-42');
|
|
123
|
+
const envelope = {
|
|
124
|
+
commandData: redis_codec_1.RedisCodec.encode(Buffer.from('cmd-data')),
|
|
125
|
+
rpc: { correlationId: 'corr-1', responseKey: 'rpc:res:corr-1' },
|
|
126
|
+
};
|
|
127
|
+
const envelopePayload = redis_codec_1.RedisCodec.encode(Buffer.from(JSON.stringify(envelope)));
|
|
128
|
+
const fields = ['data', envelopePayload, 'rpc', '1'];
|
|
129
|
+
yield processor.process('cmd:Test', 'workers', 'msg-rpc', fields, handler);
|
|
130
|
+
expect(handler).toHaveBeenCalledTimes(1);
|
|
131
|
+
expect(rpcRespond).toHaveBeenCalledWith('rpc:res:corr-1', expect.any(Buffer), 60);
|
|
132
|
+
}));
|
|
133
|
+
it('powinien nie wywoływać rpcRespond dla zwykłej wiadomości', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
134
|
+
const handler = jest.fn().mockResolvedValue('ok');
|
|
135
|
+
const fields = ['data', redis_codec_1.RedisCodec.encode(Buffer.from('normal-data'))];
|
|
136
|
+
yield processor.process('cmd:Test', 'workers', 'msg-normal', fields, handler);
|
|
137
|
+
expect(handler).toHaveBeenCalledTimes(1);
|
|
138
|
+
expect(rpcRespond).not.toHaveBeenCalled();
|
|
139
|
+
}));
|
|
140
|
+
});
|
|
141
|
+
describe('XTRIM per-stream (H2)', () => {
|
|
142
|
+
it('powinien zliczać XTRIM niezależnie per strumień', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
143
|
+
const handler = jest.fn().mockResolvedValue('ok');
|
|
144
|
+
const fields = ['data', redis_codec_1.RedisCodec.encode(Buffer.from('data'))];
|
|
145
|
+
// 9 wiadomości na stream A — nie powinno triggerować XTRIM (batchSize=10)
|
|
146
|
+
for (let i = 0; i < 9; i++) {
|
|
147
|
+
yield processor.process('cmd:StreamA', 'workers', `a-${i}`, fields, handler);
|
|
148
|
+
}
|
|
149
|
+
// 1 wiadomość na stream B
|
|
150
|
+
yield processor.process('cmd:StreamB', 'workers', 'b-0', fields, handler);
|
|
151
|
+
// Pipeline NIE powinien być wywołany — żaden stream nie osiągnął batchSize
|
|
152
|
+
const xackCalls = mockConn.xack.mock.calls;
|
|
153
|
+
expect(xackCalls.length).toBe(10);
|
|
154
|
+
// 10. wiadomość na stream A — powinno triggerować XTRIM
|
|
155
|
+
yield processor.process('cmd:StreamA', 'workers', 'a-9', fields, handler);
|
|
156
|
+
expect(mockConn.pipeline).toHaveBeenCalled();
|
|
157
|
+
}));
|
|
158
|
+
it('powinien wykonać pipeline XACK+XTRIM co batchSize', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
159
|
+
const handler = jest.fn().mockResolvedValue('ok');
|
|
160
|
+
const fields = ['data', redis_codec_1.RedisCodec.encode(Buffer.from('data'))];
|
|
161
|
+
for (let i = 0; i < 10; i++) {
|
|
162
|
+
yield processor.process('cmd:Test', 'workers', `msg-${i}`, fields, handler);
|
|
163
|
+
}
|
|
164
|
+
expect(mockConn.pipeline).toHaveBeenCalledTimes(1);
|
|
165
|
+
}));
|
|
166
|
+
it('powinien zresetować counter po XTRIM', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
167
|
+
const handler = jest.fn().mockResolvedValue('ok');
|
|
168
|
+
const fields = ['data', redis_codec_1.RedisCodec.encode(Buffer.from('data'))];
|
|
169
|
+
// Pierwsze 10 — trigger XTRIM
|
|
170
|
+
for (let i = 0; i < 10; i++) {
|
|
171
|
+
yield processor.process('cmd:Test', 'workers', `batch1-${i}`, fields, handler);
|
|
172
|
+
}
|
|
173
|
+
expect(mockConn.pipeline).toHaveBeenCalledTimes(1);
|
|
174
|
+
// Następne 9 — NIE trigger
|
|
175
|
+
for (let i = 0; i < 9; i++) {
|
|
176
|
+
yield processor.process('cmd:Test', 'workers', `batch2-${i}`, fields, handler);
|
|
177
|
+
}
|
|
178
|
+
expect(mockConn.pipeline).toHaveBeenCalledTimes(1);
|
|
179
|
+
// 20. wiadomość — trigger XTRIM ponownie
|
|
180
|
+
yield processor.process('cmd:Test', 'workers', 'batch2-9', fields, handler);
|
|
181
|
+
expect(mockConn.pipeline).toHaveBeenCalledTimes(2);
|
|
182
|
+
}));
|
|
183
|
+
});
|
|
184
|
+
});
|
|
185
|
+
//# sourceMappingURL=message-processor.spec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"message-processor.spec.js","sourceRoot":"","sources":["../../../src/command-bus/transport/message-processor.spec.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import type { ILogger } from '../../shared/types';
|
|
2
|
+
import type { ConsumerHandler } from './transport.interface';
|
|
3
|
+
import type RedisConnectionPool from '../../shared/redis/connection-pool';
|
|
4
|
+
import type { StreamConsumer } from './stream-consumer';
|
|
5
|
+
/**
|
|
6
|
+
* Konfiguracja PendingRecovery
|
|
7
|
+
*/
|
|
8
|
+
export interface PendingRecoveryOptions {
|
|
9
|
+
pool: RedisConnectionPool;
|
|
10
|
+
logger: ILogger;
|
|
11
|
+
consumerId: string;
|
|
12
|
+
maxAttempts: number;
|
|
13
|
+
claimTimeout: number;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Recovery pending wiadomości — XPENDING/XCLAIM natywny mechanizm retry
|
|
17
|
+
*
|
|
18
|
+
* Odpowiedzialności:
|
|
19
|
+
* - Periodyczne sprawdzanie stalled wiadomości (XPENDING)
|
|
20
|
+
* - Przejmowanie ich (XCLAIM) i przekazywanie do StreamConsumer.processMessage()
|
|
21
|
+
* - Dead letter dla wiadomości które przekroczyły maxAttempts
|
|
22
|
+
* - Scheduling (setInterval/clearInterval)
|
|
23
|
+
*/
|
|
24
|
+
export declare class PendingRecovery {
|
|
25
|
+
private readonly pool;
|
|
26
|
+
private readonly logger;
|
|
27
|
+
private readonly consumerId;
|
|
28
|
+
private readonly maxAttempts;
|
|
29
|
+
private readonly claimTimeout;
|
|
30
|
+
/** Intervaly recovery — do graceful shutdown */
|
|
31
|
+
private readonly recoveryIntervals;
|
|
32
|
+
constructor(options: PendingRecoveryOptions);
|
|
33
|
+
/**
|
|
34
|
+
* Uruchamia periodyczny recovery dla strumienia
|
|
35
|
+
* @param streamName - Nazwa strumienia Redis
|
|
36
|
+
* @param groupName - Nazwa grupy konsumentów
|
|
37
|
+
* @param handler - Handler przetwarzający wiadomości
|
|
38
|
+
* @param consumer - Referencja do StreamConsumer (processMessage)
|
|
39
|
+
*/
|
|
40
|
+
start(streamName: string, groupName: string, handler: ConsumerHandler, consumer: StreamConsumer): void;
|
|
41
|
+
/**
|
|
42
|
+
* Zatrzymuje wszystkie recovery intervals
|
|
43
|
+
*/
|
|
44
|
+
stop(): void;
|
|
45
|
+
/**
|
|
46
|
+
* Sprawdza i przejmuje stalled wiadomości
|
|
47
|
+
*
|
|
48
|
+
* XCLAIM zwraca dane wiadomości — recovery sam je przetwarza via consumer.processMessage()
|
|
49
|
+
* (consumer loop czyta '>' = tylko nowe, nie widzi XCLAIM'owanych)
|
|
50
|
+
*
|
|
51
|
+
* Używa pool connections (NIE dedykowane consumer conn — zajęte przez XREADGROUP BLOCK)
|
|
52
|
+
*/
|
|
53
|
+
private recoverPending;
|
|
54
|
+
}
|
|
@@ -0,0 +1,139 @@
|
|
|
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
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.PendingRecovery = void 0;
|
|
13
|
+
const error_utils_1 = require("../../shared/utils/error-utils");
|
|
14
|
+
/**
|
|
15
|
+
* Recovery pending wiadomości — XPENDING/XCLAIM natywny mechanizm retry
|
|
16
|
+
*
|
|
17
|
+
* Odpowiedzialności:
|
|
18
|
+
* - Periodyczne sprawdzanie stalled wiadomości (XPENDING)
|
|
19
|
+
* - Przejmowanie ich (XCLAIM) i przekazywanie do StreamConsumer.processMessage()
|
|
20
|
+
* - Dead letter dla wiadomości które przekroczyły maxAttempts
|
|
21
|
+
* - Scheduling (setInterval/clearInterval)
|
|
22
|
+
*/
|
|
23
|
+
class PendingRecovery {
|
|
24
|
+
constructor(options) {
|
|
25
|
+
/** Intervaly recovery — do graceful shutdown */
|
|
26
|
+
this.recoveryIntervals = [];
|
|
27
|
+
this.pool = options.pool;
|
|
28
|
+
this.logger = options.logger;
|
|
29
|
+
this.consumerId = options.consumerId;
|
|
30
|
+
this.maxAttempts = options.maxAttempts;
|
|
31
|
+
this.claimTimeout = options.claimTimeout;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Uruchamia periodyczny recovery dla strumienia
|
|
35
|
+
* @param streamName - Nazwa strumienia Redis
|
|
36
|
+
* @param groupName - Nazwa grupy konsumentów
|
|
37
|
+
* @param handler - Handler przetwarzający wiadomości
|
|
38
|
+
* @param consumer - Referencja do StreamConsumer (processMessage)
|
|
39
|
+
*/
|
|
40
|
+
start(streamName, groupName, handler, consumer) {
|
|
41
|
+
const interval = setInterval(() => {
|
|
42
|
+
void this.recoverPending(streamName, groupName, handler, consumer);
|
|
43
|
+
}, this.claimTimeout);
|
|
44
|
+
this.recoveryIntervals.push(interval);
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Zatrzymuje wszystkie recovery intervals
|
|
48
|
+
*/
|
|
49
|
+
stop() {
|
|
50
|
+
for (const interval of this.recoveryIntervals) {
|
|
51
|
+
clearInterval(interval);
|
|
52
|
+
}
|
|
53
|
+
this.recoveryIntervals.length = 0;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Sprawdza i przejmuje stalled wiadomości
|
|
57
|
+
*
|
|
58
|
+
* XCLAIM zwraca dane wiadomości — recovery sam je przetwarza via consumer.processMessage()
|
|
59
|
+
* (consumer loop czyta '>' = tylko nowe, nie widzi XCLAIM'owanych)
|
|
60
|
+
*
|
|
61
|
+
* Używa pool connections (NIE dedykowane consumer conn — zajęte przez XREADGROUP BLOCK)
|
|
62
|
+
*/
|
|
63
|
+
recoverPending(streamName, groupName, handler, consumer) {
|
|
64
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
65
|
+
try {
|
|
66
|
+
const conn = this.pool.next();
|
|
67
|
+
const pending = yield conn.xpending(streamName, groupName, '-', '+', 10);
|
|
68
|
+
if (!Array.isArray(pending) || pending.length === 0)
|
|
69
|
+
return;
|
|
70
|
+
for (const entry of pending) {
|
|
71
|
+
// entry = [messageId, consumer, idleTime, deliveryCount]
|
|
72
|
+
const pendingEntry = entry;
|
|
73
|
+
const [messageId, , idleTime, deliveryCount] = pendingEntry;
|
|
74
|
+
if (idleTime > this.claimTimeout && deliveryCount < this.maxAttempts) {
|
|
75
|
+
// Przejmij stalled wiadomość — XCLAIM zwraca dane wiadomości
|
|
76
|
+
const claimed = (yield this.pool
|
|
77
|
+
.next()
|
|
78
|
+
.xclaim(streamName, groupName, this.consumerId, this.claimTimeout, messageId));
|
|
79
|
+
this.logger.debug('Przejęto stalled wiadomość', {
|
|
80
|
+
streamName,
|
|
81
|
+
messageId,
|
|
82
|
+
deliveryCount,
|
|
83
|
+
idleTime,
|
|
84
|
+
timestamp: new Date().toISOString(),
|
|
85
|
+
});
|
|
86
|
+
// XCLAIM zwraca [[messageId, [field, value, ...]]] — przetwórz i czekaj na wynik
|
|
87
|
+
if (Array.isArray(claimed) && claimed.length > 0) {
|
|
88
|
+
const recoveryPromises = [];
|
|
89
|
+
for (const [claimedId, fields] of claimed) {
|
|
90
|
+
if (fields && fields.length >= 2) {
|
|
91
|
+
recoveryPromises.push(consumer
|
|
92
|
+
.processMessage(streamName, groupName, claimedId, fields, handler)
|
|
93
|
+
.catch((err) => this.logger.error('Błąd recovery wiadomości', {
|
|
94
|
+
streamName,
|
|
95
|
+
messageId: claimedId,
|
|
96
|
+
error: (0, error_utils_1.getErrorMessage)(err),
|
|
97
|
+
})));
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
yield Promise.allSettled(recoveryPromises);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
else if (deliveryCount >= this.maxAttempts) {
|
|
104
|
+
// D3: Dead Letter Stream — XCLAIM + XADD do DLQ przed XACK
|
|
105
|
+
const claimed = (yield this.pool
|
|
106
|
+
.next()
|
|
107
|
+
.xclaim(streamName, groupName, this.consumerId, 0, messageId));
|
|
108
|
+
if (Array.isArray(claimed) && claimed.length > 0) {
|
|
109
|
+
const [, fields] = claimed[0];
|
|
110
|
+
if (fields && fields.length >= 2) {
|
|
111
|
+
yield this.pool
|
|
112
|
+
.next()
|
|
113
|
+
.xadd(`dlq:${streamName}`, '*', ...fields, 'original_stream', streamName, 'delivery_count', String(deliveryCount));
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
yield this.pool.next().xack(streamName, groupName, messageId);
|
|
117
|
+
this.logger.error('Wiadomość przeniesiona do Dead Letter Queue', {
|
|
118
|
+
streamName,
|
|
119
|
+
dlqStream: `dlq:${streamName}`,
|
|
120
|
+
messageId,
|
|
121
|
+
deliveryCount,
|
|
122
|
+
maxAttempts: this.maxAttempts,
|
|
123
|
+
timestamp: new Date().toISOString(),
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
catch (error) {
|
|
129
|
+
this.logger.error('Błąd recovery pending wiadomości', {
|
|
130
|
+
streamName,
|
|
131
|
+
error: (0, error_utils_1.getErrorMessage)(error),
|
|
132
|
+
timestamp: new Date().toISOString(),
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
exports.PendingRecovery = PendingRecovery;
|
|
139
|
+
//# sourceMappingURL=pending-recovery.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pending-recovery.js","sourceRoot":"","sources":["../../../src/command-bus/transport/pending-recovery.ts"],"names":[],"mappings":"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"}
|