pp-command-bus 1.5.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +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 +75 -21
- package/dist/command-bus/config/command-bus-config.js +99 -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 +39 -52
- package/dist/command-bus/index.js +133 -126
- package/dist/command-bus/index.js.map +1 -1
- 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 +59 -0
- package/dist/command-bus/transport/message-processor.js +111 -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 +91 -0
- package/dist/command-bus/transport/redis-streams-transport.js +134 -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 +89 -0
- package/dist/command-bus/transport/stream-consumer.js +181 -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.0.tgz +0 -0
- package/dist/shared/redis/connection-pool.d.ts +54 -0
- package/dist/shared/redis/connection-pool.js +117 -0
- package/dist/shared/redis/connection-pool.js.map +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 → serialization/msgpack-serializer.spec.d.ts} +0 -0
- /package/dist/command-bus/{job/job-options-builder.spec.d.ts → transport/consumer-loop.spec.d.ts} +0 -0
- /package/dist/command-bus/{job/job-processor.spec.d.ts → transport/message-processor.spec.d.ts} +0 -0
- /package/dist/command-bus/{queue/queue-manager.spec.d.ts → transport/pending-recovery.spec.d.ts} +0 -0
- /package/dist/command-bus/{rpc/payload-compression.service.spec.d.ts → transport/redis-codec.spec.d.ts} +0 -0
- /package/dist/command-bus/{rpc/rpc-coordinator.spec.d.ts → transport/redis-streams-transport.spec.d.ts} +0 -0
- /package/dist/command-bus/{rpc/rpc-job-cancellation.service.spec.d.ts → transport/rpc-handler.spec.d.ts} +0 -0
- /package/dist/command-bus/{worker/worker-benchmark.spec.d.ts → transport/stream-consumer.spec.d.ts} +0 -0
- /package/dist/command-bus/{worker/worker-orchestrator.spec.d.ts → transport/stream-producer.spec.d.ts} +0 -0
- /package/dist/shared/{config/base-config.spec.d.ts → redis/connection-pool.spec.d.ts} +0 -0
|
@@ -0,0 +1,134 @@
|
|
|
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 crypto_1 = require("crypto");
|
|
13
|
+
const stream_producer_1 = require("./stream-producer");
|
|
14
|
+
const stream_consumer_1 = require("./stream-consumer");
|
|
15
|
+
const rpc_handler_1 = require("./rpc-handler");
|
|
16
|
+
const pending_recovery_1 = require("./pending-recovery");
|
|
17
|
+
/**
|
|
18
|
+
* Fasada transportu Redis Streams dla CommandBus
|
|
19
|
+
*
|
|
20
|
+
* Kompozycja 4 komponentów z jasno rozdzielonymi odpowiedzialnościami:
|
|
21
|
+
* - StreamProducer: enqueue / enqueueBatch (XADD)
|
|
22
|
+
* - StreamConsumer: consume / consumerLoop / processMessage
|
|
23
|
+
* - RpcHandler: rpcCall / rpcRespond (LPUSH/BRPOP)
|
|
24
|
+
* - PendingRecovery: XPENDING / XCLAIM / dead letter
|
|
25
|
+
*
|
|
26
|
+
* Zachowuje publiczne API ITransport — zero zmian dla CommandBus
|
|
27
|
+
*/
|
|
28
|
+
class RedisStreamsTransport {
|
|
29
|
+
constructor(options) {
|
|
30
|
+
this.pool = options.pool;
|
|
31
|
+
this.rpcPool = options.rpcPool;
|
|
32
|
+
this.logger = options.logger;
|
|
33
|
+
this.consumerId = `consumer-${process.pid}-${(0, crypto_1.randomUUID)().slice(0, 8)}`;
|
|
34
|
+
// Inicjalizacja komponentów
|
|
35
|
+
this.producer = new stream_producer_1.StreamProducer(options.pool);
|
|
36
|
+
this.rpc = new rpc_handler_1.RpcHandler(options.pool, options.rpcPool, options.serializer);
|
|
37
|
+
this.consumer = new stream_consumer_1.StreamConsumer({
|
|
38
|
+
pool: options.pool,
|
|
39
|
+
serializer: options.serializer,
|
|
40
|
+
logger: options.logger,
|
|
41
|
+
consumerId: this.consumerId,
|
|
42
|
+
batchSize: options.batchSize,
|
|
43
|
+
concurrency: options.concurrency,
|
|
44
|
+
maxRetained: options.maxRetained,
|
|
45
|
+
rpcRespond: this.rpc.rpcRespond.bind(this.rpc),
|
|
46
|
+
});
|
|
47
|
+
this.recovery = new pending_recovery_1.PendingRecovery({
|
|
48
|
+
pool: options.pool,
|
|
49
|
+
logger: options.logger,
|
|
50
|
+
consumerId: this.consumerId,
|
|
51
|
+
maxAttempts: options.maxAttempts,
|
|
52
|
+
claimTimeout: options.claimTimeout,
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Dodaje komendę do strumienia (fire-and-forget)
|
|
57
|
+
* Deleguje do StreamProducer
|
|
58
|
+
*/
|
|
59
|
+
enqueue(streamName, data) {
|
|
60
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
61
|
+
return this.producer.enqueue(streamName, data);
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Dodaje wiele komend w jednym pipeline
|
|
66
|
+
* Deleguje do StreamProducer
|
|
67
|
+
*/
|
|
68
|
+
enqueueBatch(entries) {
|
|
69
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
70
|
+
return this.producer.enqueueBatch(entries);
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Rejestruje konsumenta dla strumienia z consumer group
|
|
75
|
+
* Deleguje do StreamConsumer + uruchamia PendingRecovery
|
|
76
|
+
*/
|
|
77
|
+
consume(streamName, groupName, handler) {
|
|
78
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
79
|
+
yield this.consumer.consume(streamName, groupName, handler);
|
|
80
|
+
// Uruchom recovery loop dla pending wiadomości
|
|
81
|
+
this.recovery.start(streamName, groupName, handler, this.consumer);
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* RPC: wysyła request do strumienia i czeka na odpowiedź via BRPOP
|
|
86
|
+
* Deleguje do RpcHandler
|
|
87
|
+
*/
|
|
88
|
+
rpcCall(commandName, data, timeout) {
|
|
89
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
90
|
+
return this.rpc.rpcCall(commandName, data, timeout);
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* RPC: odpowiada na request przez LPUSH + EXPIRE
|
|
95
|
+
* Deleguje do RpcHandler
|
|
96
|
+
*/
|
|
97
|
+
rpcRespond(responseKey, data, ttl) {
|
|
98
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
99
|
+
return this.rpc.rpcRespond(responseKey, data, ttl);
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Zamyka transport gracefully
|
|
104
|
+
*
|
|
105
|
+
* Kolejność:
|
|
106
|
+
* 1. Zatrzymaj consumer.running (przerywa consumer loops)
|
|
107
|
+
* 2. Zatrzymaj recovery intervals
|
|
108
|
+
* 3. Zamknij dedykowane połączenia konsumentów (przerywa XREADGROUP BLOCK)
|
|
109
|
+
* 4. Czekaj na zakończenie consumer loops (active tasks kończą processMessage)
|
|
110
|
+
* 5. Zamknij pule połączeń
|
|
111
|
+
*/
|
|
112
|
+
close() {
|
|
113
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
114
|
+
if (!this.consumer.running)
|
|
115
|
+
return;
|
|
116
|
+
this.consumer.running = false;
|
|
117
|
+
this.logger.debug('Zamykanie RedisStreamsTransport', {
|
|
118
|
+
consumers: this.consumer.consumerCount,
|
|
119
|
+
timestamp: new Date().toISOString(),
|
|
120
|
+
});
|
|
121
|
+
// 1. Zatrzymaj recovery intervals
|
|
122
|
+
this.recovery.stop();
|
|
123
|
+
// 2. Zamknij dedykowane połączenia konsumentów — przerywa XREADGROUP BLOCK
|
|
124
|
+
this.consumer.closeConnections();
|
|
125
|
+
// 3. Czekaj na zakończenie consumer loops (active tasks kończą processMessage)
|
|
126
|
+
yield this.consumer.awaitLoops();
|
|
127
|
+
// 4. Zamknij pule połączeń — dopiero po zakończeniu wszystkich active tasks
|
|
128
|
+
yield this.pool.close();
|
|
129
|
+
yield this.rpcPool.close();
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
exports.default = RedisStreamsTransport;
|
|
134
|
+
//# sourceMappingURL=redis-streams-transport.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"redis-streams-transport.js","sourceRoot":"","sources":["../../../src/command-bus/transport/redis-streams-transport.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,420 @@
|
|
|
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 redis_streams_transport_1 = __importDefault(require("./redis-streams-transport"));
|
|
16
|
+
/**
|
|
17
|
+
* Tworzy mock Redis connection z disconnect() który przerywa blocking operations
|
|
18
|
+
* Symuluje prawdziwe zachowanie: disconnect() zamyka socket → XREADGROUP BLOCK rejectuje
|
|
19
|
+
*/
|
|
20
|
+
const createMockConnection = () => {
|
|
21
|
+
/** Rejecty pending blocking operations — disconnect() je wywołuje */
|
|
22
|
+
const pendingRejects = [];
|
|
23
|
+
return {
|
|
24
|
+
xadd: jest.fn().mockResolvedValue('1700000000000-0'),
|
|
25
|
+
xreadgroup: jest.fn().mockImplementation(() => new Promise((_resolve, reject) => {
|
|
26
|
+
pendingRejects.push(reject);
|
|
27
|
+
})),
|
|
28
|
+
xack: jest.fn().mockResolvedValue(1),
|
|
29
|
+
xgroup: jest.fn().mockResolvedValue('OK'),
|
|
30
|
+
xpending: jest.fn().mockResolvedValue([]),
|
|
31
|
+
xclaim: jest.fn().mockResolvedValue([]),
|
|
32
|
+
xtrim: jest.fn().mockResolvedValue(0),
|
|
33
|
+
brpop: jest.fn().mockResolvedValue(null),
|
|
34
|
+
lpush: jest.fn().mockResolvedValue(1),
|
|
35
|
+
expire: jest.fn().mockResolvedValue(1),
|
|
36
|
+
del: jest.fn().mockResolvedValue(1),
|
|
37
|
+
quit: jest.fn().mockResolvedValue('OK'),
|
|
38
|
+
on: jest.fn(),
|
|
39
|
+
disconnect: jest.fn().mockImplementation(() => {
|
|
40
|
+
// Przerwij pending blocking operations — symuluje zamknięcie socketa
|
|
41
|
+
const disconnectError = new Error('Connection is closed.');
|
|
42
|
+
while (pendingRejects.length > 0) {
|
|
43
|
+
const reject = pendingRejects.shift();
|
|
44
|
+
if (reject)
|
|
45
|
+
reject(disconnectError);
|
|
46
|
+
}
|
|
47
|
+
}),
|
|
48
|
+
pipeline: jest.fn().mockReturnValue({
|
|
49
|
+
xadd: jest.fn().mockReturnThis(),
|
|
50
|
+
xack: jest.fn().mockReturnThis(),
|
|
51
|
+
xtrim: jest.fn().mockReturnThis(),
|
|
52
|
+
lpush: jest.fn().mockReturnThis(),
|
|
53
|
+
expire: jest.fn().mockReturnThis(),
|
|
54
|
+
exec: jest.fn().mockResolvedValue([
|
|
55
|
+
[null, '1700000000000-0'],
|
|
56
|
+
[null, '1700000000001-0'],
|
|
57
|
+
]),
|
|
58
|
+
}),
|
|
59
|
+
};
|
|
60
|
+
};
|
|
61
|
+
const createMockPool = (conn) => ({
|
|
62
|
+
next: jest.fn().mockReturnValue(conn),
|
|
63
|
+
createDedicated: jest.fn().mockReturnValue(conn),
|
|
64
|
+
close: jest.fn().mockResolvedValue(undefined),
|
|
65
|
+
size: 4,
|
|
66
|
+
});
|
|
67
|
+
const createMockRpcPool = () => {
|
|
68
|
+
const rpcConn = createMockConnection();
|
|
69
|
+
return {
|
|
70
|
+
acquire: jest.fn().mockResolvedValue(rpcConn),
|
|
71
|
+
release: jest.fn(),
|
|
72
|
+
close: jest.fn().mockResolvedValue(undefined),
|
|
73
|
+
activeCount: 0,
|
|
74
|
+
waitingCount: 0,
|
|
75
|
+
};
|
|
76
|
+
};
|
|
77
|
+
const createMockSerializer = () => ({
|
|
78
|
+
serialize: jest.fn((data) => Buffer.from(JSON.stringify(data))),
|
|
79
|
+
deserialize: jest.fn((buf) => JSON.parse(buf.toString())),
|
|
80
|
+
});
|
|
81
|
+
const createMockLogger = () => ({
|
|
82
|
+
log: jest.fn(),
|
|
83
|
+
error: jest.fn(),
|
|
84
|
+
warn: jest.fn(),
|
|
85
|
+
debug: jest.fn(),
|
|
86
|
+
});
|
|
87
|
+
describe('RedisStreamsTransport', () => {
|
|
88
|
+
let transport;
|
|
89
|
+
let mockConn;
|
|
90
|
+
let mockPool;
|
|
91
|
+
let mockRpcPool;
|
|
92
|
+
let mockSerializer;
|
|
93
|
+
let logger;
|
|
94
|
+
beforeEach(() => {
|
|
95
|
+
jest.useFakeTimers({ legacyFakeTimers: false });
|
|
96
|
+
jest.clearAllMocks();
|
|
97
|
+
mockConn = createMockConnection();
|
|
98
|
+
mockPool = createMockPool(mockConn);
|
|
99
|
+
mockRpcPool = createMockRpcPool();
|
|
100
|
+
mockSerializer = createMockSerializer();
|
|
101
|
+
logger = createMockLogger();
|
|
102
|
+
transport = new redis_streams_transport_1.default({
|
|
103
|
+
pool: mockPool,
|
|
104
|
+
rpcPool: mockRpcPool,
|
|
105
|
+
serializer: mockSerializer,
|
|
106
|
+
logger,
|
|
107
|
+
maxRetained: 10000,
|
|
108
|
+
maxAttempts: 3,
|
|
109
|
+
claimTimeout: 30000,
|
|
110
|
+
batchSize: 10,
|
|
111
|
+
concurrency: 100,
|
|
112
|
+
});
|
|
113
|
+
});
|
|
114
|
+
afterEach(() => __awaiter(void 0, void 0, void 0, function* () {
|
|
115
|
+
yield transport.close();
|
|
116
|
+
jest.useRealTimers();
|
|
117
|
+
}));
|
|
118
|
+
describe('enqueue()', () => {
|
|
119
|
+
it('powinien wysłać dane do strumienia przez XADD', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
120
|
+
const data = Buffer.from('test-data');
|
|
121
|
+
const messageId = yield transport.enqueue('cmd:TestCommand', data);
|
|
122
|
+
// Base64: ioredis dekoduje string responses jako UTF-8, co korumpuje surowe bajty
|
|
123
|
+
expect(mockConn.xadd).toHaveBeenCalledWith('cmd:TestCommand', '*', 'data', data.toString('base64'));
|
|
124
|
+
expect(messageId).toBe('1700000000000-0');
|
|
125
|
+
}));
|
|
126
|
+
it('powinien używać połączenia z puli (round-robin)', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
127
|
+
yield transport.enqueue('cmd:Test', Buffer.from('data'));
|
|
128
|
+
expect(mockPool.next).toHaveBeenCalledTimes(1);
|
|
129
|
+
}));
|
|
130
|
+
});
|
|
131
|
+
describe('enqueueBatch()', () => {
|
|
132
|
+
it('powinien wysłać wiele komend w jednym pipeline', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
133
|
+
const entries = [
|
|
134
|
+
{ streamName: 'cmd:A', data: Buffer.from('data-a') },
|
|
135
|
+
{ streamName: 'cmd:B', data: Buffer.from('data-b') },
|
|
136
|
+
];
|
|
137
|
+
const ids = yield transport.enqueueBatch(entries);
|
|
138
|
+
expect(mockPool.next).toHaveBeenCalled();
|
|
139
|
+
expect(ids).toHaveLength(2);
|
|
140
|
+
}));
|
|
141
|
+
it('powinien zwrócić pustą tablicę dla pustego wejścia', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
142
|
+
const ids = yield transport.enqueueBatch([]);
|
|
143
|
+
expect(ids).toEqual([]);
|
|
144
|
+
}));
|
|
145
|
+
});
|
|
146
|
+
describe('consume()', () => {
|
|
147
|
+
it('powinien utworzyć consumer group i rozpocząć nasłuchiwanie', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
148
|
+
jest.useRealTimers(); // Potrzebujemy real timers dla setTimeout
|
|
149
|
+
const handler = jest.fn().mockResolvedValue(undefined);
|
|
150
|
+
// Mockujemy XREADGROUP:
|
|
151
|
+
// 1. Pierwsza wiadomość — dane do przetworzenia
|
|
152
|
+
// 2. Potem blocking promise (symuluje BLOCK 5000)
|
|
153
|
+
const consumerConn = createMockConnection();
|
|
154
|
+
// Dane w strumieniu są base64-encoded (jak w prawdziwym Redis)
|
|
155
|
+
const testPayload = Buffer.from('test-payload').toString('base64');
|
|
156
|
+
consumerConn.xreadgroup.mockResolvedValueOnce([
|
|
157
|
+
['cmd:TestCommand', [['1700000000000-0', ['data', testPayload]]]],
|
|
158
|
+
]);
|
|
159
|
+
mockPool.createDedicated.mockReturnValue(consumerConn);
|
|
160
|
+
yield transport.consume('cmd:TestCommand', 'workers', handler);
|
|
161
|
+
// Poczekaj na przetworzenie wiadomości
|
|
162
|
+
yield new Promise((r) => setTimeout(r, 50));
|
|
163
|
+
// Powinien utworzyć consumer group
|
|
164
|
+
expect(consumerConn.xgroup).toHaveBeenCalledWith('CREATE', 'cmd:TestCommand', 'workers', '0', 'MKSTREAM');
|
|
165
|
+
// Powinien wywołać handler z danymi
|
|
166
|
+
expect(handler).toHaveBeenCalledTimes(1);
|
|
167
|
+
expect(handler).toHaveBeenCalledWith(expect.any(Buffer));
|
|
168
|
+
// XACK idzie przez pool connection (nie dedykowane consumer conn — XREADGROUP BLOCK)
|
|
169
|
+
expect(mockConn.xack).toHaveBeenCalledWith('cmd:TestCommand', 'workers', '1700000000000-0');
|
|
170
|
+
}));
|
|
171
|
+
it('powinien obsłużyć błąd tworzenia grupy jeśli już istnieje', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
172
|
+
const handler = jest.fn().mockResolvedValue(undefined);
|
|
173
|
+
const consumerConn = createMockConnection();
|
|
174
|
+
consumerConn.xgroup.mockRejectedValueOnce(new Error('BUSYGROUP Consumer Group name already exists'));
|
|
175
|
+
mockPool.createDedicated.mockReturnValue(consumerConn);
|
|
176
|
+
// Nie powinien rzucić błędu
|
|
177
|
+
yield transport.consume('cmd:Test', 'workers', handler);
|
|
178
|
+
}));
|
|
179
|
+
});
|
|
180
|
+
describe('rpcCall()', () => {
|
|
181
|
+
it('powinien wysłać komendę i czekać na odpowiedź przez BRPOP', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
182
|
+
const responseData = Buffer.from(JSON.stringify({ result: 42 }));
|
|
183
|
+
const rpcConn = createMockConnection();
|
|
184
|
+
// BRPOP zwraca base64-encoded string (rpcRespond koduje dane jako base64)
|
|
185
|
+
rpcConn.brpop.mockResolvedValue(['rpc:res:test-id', responseData.toString('base64')]);
|
|
186
|
+
mockRpcPool.acquire.mockResolvedValue(rpcConn);
|
|
187
|
+
const result = yield transport.rpcCall('TestCommand', Buffer.from('request-data'), 5000);
|
|
188
|
+
// Powinien wysłać komendę do strumienia
|
|
189
|
+
expect(mockConn.xadd).toHaveBeenCalled();
|
|
190
|
+
// Powinien pobrać połączenie z RPC pool
|
|
191
|
+
expect(mockRpcPool.acquire).toHaveBeenCalled();
|
|
192
|
+
// Powinien czekać na odpowiedź przez BRPOP
|
|
193
|
+
expect(rpcConn.brpop).toHaveBeenCalled();
|
|
194
|
+
// Powinien zwolnić połączenie po zakończeniu
|
|
195
|
+
expect(mockRpcPool.release).toHaveBeenCalledWith(rpcConn);
|
|
196
|
+
expect(result).toBeInstanceOf(Buffer);
|
|
197
|
+
}));
|
|
198
|
+
it('powinien rzucić błąd przy timeout (BRPOP zwraca null)', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
199
|
+
const rpcConn = createMockConnection();
|
|
200
|
+
rpcConn.brpop.mockResolvedValue(null);
|
|
201
|
+
mockRpcPool.acquire.mockResolvedValue(rpcConn);
|
|
202
|
+
yield expect(transport.rpcCall('TestCommand', Buffer.from('data'), 1000)).rejects.toThrow('RPC timeout');
|
|
203
|
+
// Powinien zwolnić połączenie nawet przy błędzie
|
|
204
|
+
expect(mockRpcPool.release).toHaveBeenCalledWith(rpcConn);
|
|
205
|
+
}));
|
|
206
|
+
});
|
|
207
|
+
describe('rpcRespond()', () => {
|
|
208
|
+
it('powinien wysłać odpowiedź przez pipeline LPUSH + EXPIRE', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
209
|
+
const responseData = Buffer.from('response');
|
|
210
|
+
yield transport.rpcRespond('rpc:res:test-id', responseData, 60);
|
|
211
|
+
// Powinien użyć pipeline
|
|
212
|
+
expect(mockConn.pipeline).toHaveBeenCalled();
|
|
213
|
+
}));
|
|
214
|
+
});
|
|
215
|
+
describe('XTRIM throttling (H1+H2)', () => {
|
|
216
|
+
it('powinien wykonać XTRIM co batchSize wiadomości', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
217
|
+
jest.useRealTimers();
|
|
218
|
+
const handler = jest.fn().mockResolvedValue(undefined);
|
|
219
|
+
const consumerConn = createMockConnection();
|
|
220
|
+
// Symuluj 10 wiadomości (batchSize = 10)
|
|
221
|
+
const testPayload = Buffer.from('payload').toString('base64');
|
|
222
|
+
const messages = Array.from({ length: 10 }, (_, i) => [
|
|
223
|
+
`170000000000${i}-0`,
|
|
224
|
+
['data', testPayload],
|
|
225
|
+
]);
|
|
226
|
+
consumerConn.xreadgroup.mockResolvedValueOnce([['cmd:Test', messages]]);
|
|
227
|
+
mockPool.createDedicated.mockReturnValue(consumerConn);
|
|
228
|
+
yield transport.consume('cmd:Test', 'workers', handler);
|
|
229
|
+
// Poczekaj na przetworzenie
|
|
230
|
+
yield new Promise((r) => setTimeout(r, 100));
|
|
231
|
+
// Pipeline powinien być użyty dokładnie raz (10. wiadomość = batchSize)
|
|
232
|
+
// Wiadomości 1-9: sam XACK, wiadomość 10: pipeline XACK+XTRIM
|
|
233
|
+
const pipelineCalls = mockConn.pipeline.mock.calls.length;
|
|
234
|
+
expect(pipelineCalls).toBeGreaterThanOrEqual(1);
|
|
235
|
+
// XTRIM NIE powinien być wywołany bezpośrednio (fire-and-forget usunięty)
|
|
236
|
+
expect(mockConn.xtrim).not.toHaveBeenCalled();
|
|
237
|
+
}));
|
|
238
|
+
});
|
|
239
|
+
describe('RPC marker field (H3)', () => {
|
|
240
|
+
it('powinien dodać marker rpc do XADD dla RPC', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
241
|
+
const rpcConn = createMockConnection();
|
|
242
|
+
const responseData = Buffer.from(JSON.stringify({ result: 42 }));
|
|
243
|
+
rpcConn.brpop.mockResolvedValue(['rpc:res:test-id', responseData.toString('base64')]);
|
|
244
|
+
mockRpcPool.acquire.mockResolvedValue(rpcConn);
|
|
245
|
+
yield transport.rpcCall('TestCommand', Buffer.from('request-data'), 5000);
|
|
246
|
+
// XADD powinien mieć 6 argumentów: streamName, *, 'data', value, 'rpc', '1'
|
|
247
|
+
const xaddCall = mockConn.xadd.mock.calls[0];
|
|
248
|
+
expect(xaddCall).toContain('rpc');
|
|
249
|
+
expect(xaddCall).toContain('1');
|
|
250
|
+
}));
|
|
251
|
+
it('powinien użyć markera rpc do identyfikacji RPC envelope', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
252
|
+
jest.useRealTimers();
|
|
253
|
+
const handler = jest.fn().mockResolvedValue('rpc-result');
|
|
254
|
+
const consumerConn = createMockConnection();
|
|
255
|
+
// Symuluj RPC wiadomość z markerem
|
|
256
|
+
const envelope = {
|
|
257
|
+
commandData: Buffer.from('cmd-data').toString('base64'),
|
|
258
|
+
rpc: { correlationId: 'test', responseKey: 'rpc:res:test' },
|
|
259
|
+
};
|
|
260
|
+
const envelopePayload = Buffer.from(JSON.stringify(envelope)).toString('base64');
|
|
261
|
+
consumerConn.xreadgroup.mockResolvedValueOnce([
|
|
262
|
+
['cmd:Test', [['msg-rpc', ['data', envelopePayload, 'rpc', '1']]]],
|
|
263
|
+
]);
|
|
264
|
+
mockPool.createDedicated.mockReturnValue(consumerConn);
|
|
265
|
+
yield transport.consume('cmd:Test', 'workers', handler);
|
|
266
|
+
yield new Promise((r) => setTimeout(r, 50));
|
|
267
|
+
// Handler powinien być wywołany
|
|
268
|
+
expect(handler).toHaveBeenCalledTimes(1);
|
|
269
|
+
}));
|
|
270
|
+
it('powinien obsługiwać zwykłe komendy bez markera', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
271
|
+
jest.useRealTimers();
|
|
272
|
+
const handler = jest.fn().mockResolvedValue(undefined);
|
|
273
|
+
const consumerConn = createMockConnection();
|
|
274
|
+
// Zwykła komenda — bez markera 'rpc'
|
|
275
|
+
const testPayload = Buffer.from('normal-command').toString('base64');
|
|
276
|
+
consumerConn.xreadgroup.mockResolvedValueOnce([
|
|
277
|
+
['cmd:Test', [['msg-normal', ['data', testPayload]]]],
|
|
278
|
+
]);
|
|
279
|
+
mockPool.createDedicated.mockReturnValue(consumerConn);
|
|
280
|
+
yield transport.consume('cmd:Test', 'workers', handler);
|
|
281
|
+
yield new Promise((r) => setTimeout(r, 50));
|
|
282
|
+
// Handler powinien być wywołany z surowymi danymi (nie RPC)
|
|
283
|
+
expect(handler).toHaveBeenCalledTimes(1);
|
|
284
|
+
expect(handler).toHaveBeenCalledWith(expect.any(Buffer));
|
|
285
|
+
}));
|
|
286
|
+
});
|
|
287
|
+
describe('close()', () => {
|
|
288
|
+
it('powinien zamknąć transport gracefully', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
289
|
+
yield transport.close();
|
|
290
|
+
expect(mockPool.close).toHaveBeenCalled();
|
|
291
|
+
expect(mockRpcPool.close).toHaveBeenCalled();
|
|
292
|
+
}));
|
|
293
|
+
it('powinien być idempotentny (drugie close nie rzuca)', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
294
|
+
yield transport.close();
|
|
295
|
+
yield transport.close();
|
|
296
|
+
}));
|
|
297
|
+
it('powinien czekać na zakończenie aktywnych processMessage przed zamknięciem puli', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
298
|
+
jest.useRealTimers();
|
|
299
|
+
// Przygotuj consumer z wolnym handlerem
|
|
300
|
+
let handlerResolve;
|
|
301
|
+
const handlerPromise = new Promise((resolve) => {
|
|
302
|
+
handlerResolve = resolve;
|
|
303
|
+
});
|
|
304
|
+
const handler = jest.fn().mockReturnValue(handlerPromise);
|
|
305
|
+
const consumerConn = createMockConnection();
|
|
306
|
+
const testPayload = Buffer.from('test-payload').toString('base64');
|
|
307
|
+
// Pierwsza wiadomość → przetworzenie, kolejne → domyślne interruptible blocking
|
|
308
|
+
consumerConn.xreadgroup.mockResolvedValueOnce([
|
|
309
|
+
['cmd:Test', [['1700000000000-0', ['data', testPayload]]]],
|
|
310
|
+
]);
|
|
311
|
+
mockPool.createDedicated.mockReturnValue(consumerConn);
|
|
312
|
+
yield transport.consume('cmd:Test', 'workers', handler);
|
|
313
|
+
// Poczekaj na start przetwarzania
|
|
314
|
+
yield new Promise((r) => setTimeout(r, 50));
|
|
315
|
+
expect(handler).toHaveBeenCalledTimes(1);
|
|
316
|
+
// Zamknij transport — close powinno czekać na handler
|
|
317
|
+
const closePromise = transport.close();
|
|
318
|
+
// Handler jeszcze pracuje — pool.close() jeszcze nie powinien być wywołany
|
|
319
|
+
yield new Promise((r) => setTimeout(r, 20));
|
|
320
|
+
// Zakończ handler
|
|
321
|
+
handlerResolve();
|
|
322
|
+
yield closePromise;
|
|
323
|
+
// Pool zamknięty dopiero po zakończeniu handlera
|
|
324
|
+
expect(mockPool.close).toHaveBeenCalled();
|
|
325
|
+
}));
|
|
326
|
+
});
|
|
327
|
+
describe('recoverPending()', () => {
|
|
328
|
+
/**
|
|
329
|
+
* Pomocnik — wyciąga wewnętrzne komponenty fasady do testowania recovery
|
|
330
|
+
* Po refaktorze SRP: recoverPending jest w PendingRecovery, processMessage w StreamConsumer
|
|
331
|
+
*/
|
|
332
|
+
const getInternals = (t) => {
|
|
333
|
+
const any = t;
|
|
334
|
+
return {
|
|
335
|
+
recovery: any['recovery'],
|
|
336
|
+
consumer: any['consumer'],
|
|
337
|
+
};
|
|
338
|
+
};
|
|
339
|
+
it('powinien przetworzyć wiadomość po XCLAIM', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
340
|
+
jest.useRealTimers();
|
|
341
|
+
const handler = jest.fn().mockResolvedValue('ok');
|
|
342
|
+
const consumerConn = createMockConnection();
|
|
343
|
+
mockPool.createDedicated.mockReturnValue(consumerConn);
|
|
344
|
+
// Symuluj XPENDING z 1 stalled wiadomością
|
|
345
|
+
const testPayload = Buffer.from('recovered-data').toString('base64');
|
|
346
|
+
mockConn.xpending.mockResolvedValue([['msg-1', 'consumer-old', 60000, 1]]);
|
|
347
|
+
// XCLAIM zwraca dane wiadomości
|
|
348
|
+
mockConn.xclaim.mockResolvedValue([['msg-1', ['data', testPayload]]]);
|
|
349
|
+
yield transport.consume('cmd:Test', 'workers', handler);
|
|
350
|
+
// Wywołujemy recoverPending bezpośrednio przez wewnętrzny komponent recovery
|
|
351
|
+
const { recovery, consumer } = getInternals(transport);
|
|
352
|
+
yield recovery['recoverPending']('cmd:Test', 'workers', handler, consumer);
|
|
353
|
+
// Poczekaj na przetworzenie
|
|
354
|
+
yield new Promise((r) => setTimeout(r, 50));
|
|
355
|
+
// Handler powinien być wywołany z recovered danymi
|
|
356
|
+
expect(handler).toHaveBeenCalledWith(expect.any(Buffer));
|
|
357
|
+
// XACK powinno być wywołane
|
|
358
|
+
expect(mockConn.xack).toHaveBeenCalledWith('cmd:Test', 'workers', 'msg-1');
|
|
359
|
+
}));
|
|
360
|
+
it('powinien przenieść do DLQ po maxAttempts (D3)', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
361
|
+
jest.useRealTimers();
|
|
362
|
+
const handler = jest.fn().mockResolvedValue('ok');
|
|
363
|
+
const consumerConn = createMockConnection();
|
|
364
|
+
mockPool.createDedicated.mockReturnValue(consumerConn);
|
|
365
|
+
const testPayload = Buffer.from('dead-data').toString('base64');
|
|
366
|
+
// Wiadomość z deliveryCount >= maxAttempts (3)
|
|
367
|
+
mockConn.xpending.mockResolvedValue([['msg-dead', 'consumer-old', 60000, 3]]);
|
|
368
|
+
// D3: XCLAIM teraz jest wywoływany żeby pobrać dane do DLQ
|
|
369
|
+
mockConn.xclaim.mockResolvedValue([['msg-dead', ['data', testPayload]]]);
|
|
370
|
+
yield transport.consume('cmd:Test', 'workers', handler);
|
|
371
|
+
const { recovery, consumer } = getInternals(transport);
|
|
372
|
+
yield recovery['recoverPending']('cmd:Test', 'workers', handler, consumer);
|
|
373
|
+
// XCLAIM powinno być wywołane (pobiera dane do DLQ)
|
|
374
|
+
expect(mockConn.xclaim).toHaveBeenCalled();
|
|
375
|
+
// XADD do DLQ strumienia
|
|
376
|
+
expect(mockConn.xadd).toHaveBeenCalledWith('dlq:cmd:Test', '*', 'data', testPayload, 'original_stream', 'cmd:Test', 'delivery_count', '3');
|
|
377
|
+
// XACK po przeniesieniu do DLQ
|
|
378
|
+
expect(mockConn.xack).toHaveBeenCalledWith('cmd:Test', 'workers', 'msg-dead');
|
|
379
|
+
// Handler NIE powinien być wywołany
|
|
380
|
+
expect(handler).not.toHaveBeenCalled();
|
|
381
|
+
// Powinien zalogować
|
|
382
|
+
expect(logger.error).toHaveBeenCalledWith('Wiadomość przeniesiona do Dead Letter Queue', expect.objectContaining({
|
|
383
|
+
messageId: 'msg-dead',
|
|
384
|
+
dlqStream: 'dlq:cmd:Test',
|
|
385
|
+
deliveryCount: 3,
|
|
386
|
+
}));
|
|
387
|
+
}));
|
|
388
|
+
it('nie powinien duplikować gdy wiadomość jest już przetwarzana', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
389
|
+
jest.useRealTimers();
|
|
390
|
+
// Handler który trwa długo
|
|
391
|
+
let handlerCallCount = 0;
|
|
392
|
+
const handler = jest.fn().mockImplementation(() => __awaiter(void 0, void 0, void 0, function* () {
|
|
393
|
+
handlerCallCount++;
|
|
394
|
+
yield new Promise((r) => setTimeout(r, 100));
|
|
395
|
+
return 'ok';
|
|
396
|
+
}));
|
|
397
|
+
const consumerConn = createMockConnection();
|
|
398
|
+
const testPayload = Buffer.from('dedup-data').toString('base64');
|
|
399
|
+
// Consumer loop dostaje wiadomość — po niej domyślne interruptible blocking
|
|
400
|
+
consumerConn.xreadgroup.mockResolvedValueOnce([
|
|
401
|
+
['cmd:Test', [['msg-dedup', ['data', testPayload]]]],
|
|
402
|
+
]);
|
|
403
|
+
mockPool.createDedicated.mockReturnValue(consumerConn);
|
|
404
|
+
// XCLAIM też zwraca tę samą wiadomość
|
|
405
|
+
mockConn.xpending.mockResolvedValue([['msg-dedup', 'consumer-old', 60000, 1]]);
|
|
406
|
+
mockConn.xclaim.mockResolvedValue([['msg-dedup', ['data', testPayload]]]);
|
|
407
|
+
yield transport.consume('cmd:Test', 'workers', handler);
|
|
408
|
+
// Poczekaj aż consumer loop zacznie przetwarzać
|
|
409
|
+
yield new Promise((r) => setTimeout(r, 30));
|
|
410
|
+
// Recovery próbuje XCLAIM tej samej wiadomości — przez wewnętrzny komponent
|
|
411
|
+
const { recovery, consumer } = getInternals(transport);
|
|
412
|
+
yield recovery['recoverPending']('cmd:Test', 'workers', handler, consumer);
|
|
413
|
+
// Poczekaj na zakończenie
|
|
414
|
+
yield new Promise((r) => setTimeout(r, 200));
|
|
415
|
+
// Handler powinien być wywołany tylko RAZ (deduplicacja)
|
|
416
|
+
expect(handlerCallCount).toBe(1);
|
|
417
|
+
}));
|
|
418
|
+
});
|
|
419
|
+
});
|
|
420
|
+
//# sourceMappingURL=redis-streams-transport.spec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"redis-streams-transport.spec.js","sourceRoot":"","sources":["../../../src/command-bus/transport/redis-streams-transport.spec.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { ISerializer } from '../serialization/serializer.interface';
|
|
2
|
+
import type { IRpcTransport, RpcMessageMetadata } from './transport.interface';
|
|
3
|
+
import type RedisConnectionPool from '../../shared/redis/connection-pool';
|
|
4
|
+
import type RpcConnectionPool from '../../shared/redis/rpc-connection-pool';
|
|
5
|
+
/**
|
|
6
|
+
* Dane envelope dla RPC — wiadomość w strumieniu zawiera zarówno
|
|
7
|
+
* dane komendy jak i metadane RPC do routingu odpowiedzi
|
|
8
|
+
*/
|
|
9
|
+
export interface RpcEnvelope {
|
|
10
|
+
/** Surowe dane komendy zakodowane jako base64 string */
|
|
11
|
+
commandData: string;
|
|
12
|
+
/** Metadane RPC */
|
|
13
|
+
rpc: RpcMessageMetadata;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Handler RPC — odpowiada za request/response przez Redis Streams + LPUSH/BRPOP
|
|
17
|
+
* Jedna odpowiedzialność: RPC call i respond
|
|
18
|
+
*/
|
|
19
|
+
export declare class RpcHandler implements IRpcTransport {
|
|
20
|
+
private readonly pool;
|
|
21
|
+
private readonly rpcPool;
|
|
22
|
+
private readonly serializer;
|
|
23
|
+
constructor(pool: RedisConnectionPool, rpcPool: RpcConnectionPool, serializer: ISerializer);
|
|
24
|
+
/**
|
|
25
|
+
* RPC: wysyła request do strumienia i czeka na odpowiedź via BRPOP
|
|
26
|
+
*
|
|
27
|
+
* Flow (4 komendy Redis):
|
|
28
|
+
* 1. XADD — komenda z metadanymi RPC do strumienia
|
|
29
|
+
* 2. BRPOP — czekaj na odpowiedź na dedykowanym połączeniu
|
|
30
|
+
* 3. Worker: LPUSH — odpowiedź na klucz
|
|
31
|
+
* 4. DEL — cleanup klucza (TTL safety net)
|
|
32
|
+
*/
|
|
33
|
+
rpcCall(commandName: string, data: Buffer, timeout: number): Promise<Buffer>;
|
|
34
|
+
/**
|
|
35
|
+
* RPC: odpowiada na request przez LPUSH + EXPIRE w jednym pipeline
|
|
36
|
+
* Wywoływane przez worker po przetworzeniu komendy RPC
|
|
37
|
+
*/
|
|
38
|
+
rpcRespond(responseKey: string, data: Buffer, ttl: number): Promise<void>;
|
|
39
|
+
}
|