pp-command-bus 1.4.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 +402 -1113
- package/dist/command-bus/command-bus.spec.js +144 -370
- package/dist/command-bus/command-bus.spec.js.map +1 -1
- package/dist/command-bus/command.d.ts +23 -5
- package/dist/command-bus/command.js +20 -34
- 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 +49 -14
- 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 +9 -80
- package/dist/examples/rpc-throughput.demo.js +24 -22
- package/dist/examples/rpc-throughput.demo.js.map +1 -1
- package/dist/examples/rpc.demo.js +47 -53
- 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 -437
- 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 -51
- package/dist/command-bus/rpc/payload-compression.service.js +0 -218
- package/dist/command-bus/rpc/payload-compression.service.js.map +0 -1
- package/dist/command-bus/rpc/payload-compression.service.spec.js +0 -379
- 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 -622
- 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 -203
- 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 -363
- package/dist/examples/rpc-compression.demo.js.map +0 -1
- package/dist/examples/rpc-resilience.demo.d.ts +0 -11
- package/dist/examples/rpc-resilience.demo.js +0 -235
- package/dist/examples/rpc-resilience.demo.js.map +0 -1
- package/dist/pp-command-bus-1.4.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,87 @@
|
|
|
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.RpcHandler = void 0;
|
|
13
|
+
const crypto_1 = require("crypto");
|
|
14
|
+
const redis_codec_1 = require("./redis-codec");
|
|
15
|
+
/**
|
|
16
|
+
* Handler RPC — odpowiada za request/response przez Redis Streams + LPUSH/BRPOP
|
|
17
|
+
* Jedna odpowiedzialność: RPC call i respond
|
|
18
|
+
*/
|
|
19
|
+
class RpcHandler {
|
|
20
|
+
constructor(pool, rpcPool, serializer) {
|
|
21
|
+
this.pool = pool;
|
|
22
|
+
this.rpcPool = rpcPool;
|
|
23
|
+
this.serializer = serializer;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* RPC: wysyła request do strumienia i czeka na odpowiedź via BRPOP
|
|
27
|
+
*
|
|
28
|
+
* Flow (4 komendy Redis):
|
|
29
|
+
* 1. XADD — komenda z metadanymi RPC do strumienia
|
|
30
|
+
* 2. BRPOP — czekaj na odpowiedź na dedykowanym połączeniu
|
|
31
|
+
* 3. Worker: LPUSH — odpowiedź na klucz
|
|
32
|
+
* 4. DEL — cleanup klucza (TTL safety net)
|
|
33
|
+
*/
|
|
34
|
+
rpcCall(commandName, data, timeout) {
|
|
35
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
36
|
+
// M1: Walidacja timeout — zapobiega infinite BRPOP przy 0/negatywnych/Infinity
|
|
37
|
+
if (!Number.isFinite(timeout) || timeout <= 0) {
|
|
38
|
+
throw new Error(`Nieprawidłowy timeout RPC: ${timeout}ms`);
|
|
39
|
+
}
|
|
40
|
+
const correlationId = (0, crypto_1.randomUUID)();
|
|
41
|
+
const responseKey = `rpc:res:${correlationId}`;
|
|
42
|
+
const envelope = {
|
|
43
|
+
commandData: redis_codec_1.RedisCodec.encode(data),
|
|
44
|
+
rpc: { correlationId, responseKey },
|
|
45
|
+
};
|
|
46
|
+
const envelopeBuffer = this.serializer.serialize(envelope);
|
|
47
|
+
// Wyślij do strumienia z markerem 'rpc' do identyfikacji
|
|
48
|
+
const poolConn = this.pool.next();
|
|
49
|
+
yield poolConn.xadd(`cmd:${commandName}`, '*', 'data', redis_codec_1.RedisCodec.encode(envelopeBuffer), 'rpc', '1');
|
|
50
|
+
// Pobierz dedykowane połączenie dla BRPOP (blocking)
|
|
51
|
+
const rpcConn = yield this.rpcPool.acquire();
|
|
52
|
+
try {
|
|
53
|
+
const timeoutSec = Math.max(1, Math.ceil(timeout / 1000));
|
|
54
|
+
const result = yield rpcConn.brpop(responseKey, timeoutSec);
|
|
55
|
+
if (!result) {
|
|
56
|
+
// C2: await DEL z fallback EXPIRE — zapobiega orphaned Redis keys
|
|
57
|
+
yield poolConn.del(responseKey).catch(() => {
|
|
58
|
+
// Fallback: EXPIRE zapewnia automatyczne usunięcie klucza po 120s
|
|
59
|
+
void poolConn.expire(responseKey, 120).catch(() => undefined);
|
|
60
|
+
});
|
|
61
|
+
// M2: bez correlationId w error message — zapobiega information leakage
|
|
62
|
+
throw new Error(`RPC timeout dla komendy ${commandName} (${timeout}ms)`);
|
|
63
|
+
}
|
|
64
|
+
const value = result[1];
|
|
65
|
+
return redis_codec_1.RedisCodec.decode(value);
|
|
66
|
+
}
|
|
67
|
+
finally {
|
|
68
|
+
this.rpcPool.release(rpcConn);
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* RPC: odpowiada na request przez LPUSH + EXPIRE w jednym pipeline
|
|
74
|
+
* Wywoływane przez worker po przetworzeniu komendy RPC
|
|
75
|
+
*/
|
|
76
|
+
rpcRespond(responseKey, data, ttl) {
|
|
77
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
78
|
+
const conn = this.pool.next();
|
|
79
|
+
const pipeline = conn.pipeline();
|
|
80
|
+
pipeline.lpush(responseKey, redis_codec_1.RedisCodec.encode(data));
|
|
81
|
+
pipeline.expire(responseKey, ttl);
|
|
82
|
+
yield pipeline.exec();
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
exports.RpcHandler = RpcHandler;
|
|
87
|
+
//# sourceMappingURL=rpc-handler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rpc-handler.js","sourceRoot":"","sources":["../../../src/command-bus/transport/rpc-handler.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,157 @@
|
|
|
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 rpc_handler_1 = require("./rpc-handler");
|
|
13
|
+
const redis_codec_1 = require("./redis-codec");
|
|
14
|
+
/**
|
|
15
|
+
* Mock serializera — JSON roundtrip
|
|
16
|
+
*/
|
|
17
|
+
function createMockSerializer() {
|
|
18
|
+
return {
|
|
19
|
+
serialize: jest.fn((data) => Buffer.from(JSON.stringify(data))),
|
|
20
|
+
deserialize: jest.fn((buf) => JSON.parse(buf.toString())),
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Mock połączenia Redis
|
|
25
|
+
*/
|
|
26
|
+
function createMockConnection() {
|
|
27
|
+
return {
|
|
28
|
+
xadd: jest.fn().mockResolvedValue('1700000000000-0'),
|
|
29
|
+
del: jest.fn().mockResolvedValue(1),
|
|
30
|
+
expire: jest.fn().mockResolvedValue(1),
|
|
31
|
+
brpop: jest.fn().mockResolvedValue(null),
|
|
32
|
+
lpush: jest.fn().mockResolvedValue(1),
|
|
33
|
+
pipeline: jest.fn().mockReturnValue({
|
|
34
|
+
lpush: jest.fn().mockReturnThis(),
|
|
35
|
+
expire: jest.fn().mockReturnThis(),
|
|
36
|
+
exec: jest.fn().mockResolvedValue([
|
|
37
|
+
[null, 1],
|
|
38
|
+
[null, 1],
|
|
39
|
+
]),
|
|
40
|
+
}),
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
function createMockPool() {
|
|
44
|
+
const conn = createMockConnection();
|
|
45
|
+
return {
|
|
46
|
+
pool: { next: jest.fn().mockReturnValue(conn) },
|
|
47
|
+
conn,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
function createMockRpcPool() {
|
|
51
|
+
const rpcConn = createMockConnection();
|
|
52
|
+
return {
|
|
53
|
+
rpcPool: {
|
|
54
|
+
acquire: jest.fn().mockResolvedValue(rpcConn),
|
|
55
|
+
release: jest.fn(),
|
|
56
|
+
},
|
|
57
|
+
rpcConn,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
describe('RpcHandler', () => {
|
|
61
|
+
let handler;
|
|
62
|
+
let mockConn;
|
|
63
|
+
let rpcConn;
|
|
64
|
+
let mockPool;
|
|
65
|
+
let mockRpcPool;
|
|
66
|
+
let serializer;
|
|
67
|
+
beforeEach(() => {
|
|
68
|
+
jest.clearAllMocks();
|
|
69
|
+
const poolMock = createMockPool();
|
|
70
|
+
const rpcPoolMock = createMockRpcPool();
|
|
71
|
+
mockPool = poolMock.pool;
|
|
72
|
+
mockConn = poolMock.conn;
|
|
73
|
+
mockRpcPool = rpcPoolMock.rpcPool;
|
|
74
|
+
rpcConn = rpcPoolMock.rpcConn;
|
|
75
|
+
serializer = createMockSerializer();
|
|
76
|
+
handler = new rpc_handler_1.RpcHandler(mockPool, mockRpcPool, serializer);
|
|
77
|
+
});
|
|
78
|
+
describe('rpcCall()', () => {
|
|
79
|
+
it('powinien wysłać komendę do strumienia i czekać na odpowiedź', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
80
|
+
const responseData = Buffer.from(JSON.stringify({ result: 42 }));
|
|
81
|
+
rpcConn.brpop.mockResolvedValue(['rpc:res:test', redis_codec_1.RedisCodec.encode(responseData)]);
|
|
82
|
+
const result = yield handler.rpcCall('TestCommand', Buffer.from('request'), 5000);
|
|
83
|
+
// Powinien wysłać XADD z markerem rpc
|
|
84
|
+
expect(mockConn.xadd).toHaveBeenCalledWith('cmd:TestCommand', '*', 'data', expect.any(String), 'rpc', '1');
|
|
85
|
+
// Powinien pobrać i zwolnić połączenie RPC
|
|
86
|
+
expect(mockRpcPool.acquire).toHaveBeenCalled();
|
|
87
|
+
expect(mockRpcPool.release).toHaveBeenCalled();
|
|
88
|
+
expect(result).toBeInstanceOf(Buffer);
|
|
89
|
+
}));
|
|
90
|
+
it('powinien rzucić timeout gdy BRPOP zwraca null', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
91
|
+
rpcConn.brpop.mockResolvedValue(null);
|
|
92
|
+
yield expect(handler.rpcCall('TestCommand', Buffer.from('data'), 1000)).rejects.toThrow('RPC timeout dla komendy TestCommand (1000ms)');
|
|
93
|
+
}));
|
|
94
|
+
it('powinien zwolnić połączenie RPC nawet przy timeout', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
95
|
+
rpcConn.brpop.mockResolvedValue(null);
|
|
96
|
+
yield expect(handler.rpcCall('TestCommand', Buffer.from('data'), 1000)).rejects.toThrow();
|
|
97
|
+
expect(mockRpcPool.release).toHaveBeenCalledWith(rpcConn);
|
|
98
|
+
}));
|
|
99
|
+
it('powinien await DEL na timeout (C2)', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
100
|
+
rpcConn.brpop.mockResolvedValue(null);
|
|
101
|
+
mockConn.del.mockResolvedValue(1);
|
|
102
|
+
yield expect(handler.rpcCall('TestCommand', Buffer.from('data'), 1000)).rejects.toThrow();
|
|
103
|
+
expect(mockConn.del).toHaveBeenCalled();
|
|
104
|
+
}));
|
|
105
|
+
it('powinien ustawić EXPIRE jako fallback gdy DEL failuje (C2)', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
106
|
+
rpcConn.brpop.mockResolvedValue(null);
|
|
107
|
+
mockConn.del.mockRejectedValue(new Error('Connection lost'));
|
|
108
|
+
yield expect(handler.rpcCall('TestCommand', Buffer.from('data'), 1000)).rejects.toThrow('RPC timeout');
|
|
109
|
+
expect(mockConn.del).toHaveBeenCalled();
|
|
110
|
+
expect(mockConn.expire).toHaveBeenCalledWith(expect.stringContaining('rpc:res:'), 120);
|
|
111
|
+
}));
|
|
112
|
+
it('nie powinien rzucać gdy zarówno DEL jak i EXPIRE failują (C2)', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
113
|
+
rpcConn.brpop.mockResolvedValue(null);
|
|
114
|
+
mockConn.del.mockRejectedValue(new Error('Connection lost'));
|
|
115
|
+
mockConn.expire.mockRejectedValue(new Error('Connection lost'));
|
|
116
|
+
// Powinien rzucić TYLKO RPC timeout, nie błąd z DEL/EXPIRE
|
|
117
|
+
yield expect(handler.rpcCall('TestCommand', Buffer.from('data'), 1000)).rejects.toThrow('RPC timeout');
|
|
118
|
+
}));
|
|
119
|
+
it('nie powinien zawierać correlationId w error message (M2)', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
120
|
+
rpcConn.brpop.mockResolvedValue(null);
|
|
121
|
+
try {
|
|
122
|
+
yield handler.rpcCall('TestCommand', Buffer.from('data'), 1000);
|
|
123
|
+
}
|
|
124
|
+
catch (error) {
|
|
125
|
+
const message = error.message;
|
|
126
|
+
expect(message).not.toContain('correlationId');
|
|
127
|
+
}
|
|
128
|
+
}));
|
|
129
|
+
it('powinien rzucić błąd przy timeout 0 (M1)', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
130
|
+
yield expect(handler.rpcCall('TestCommand', Buffer.from('data'), 0)).rejects.toThrow('Nieprawidłowy timeout RPC: 0ms');
|
|
131
|
+
}));
|
|
132
|
+
it('powinien rzucić błąd przy negatywnym timeout (M1)', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
133
|
+
yield expect(handler.rpcCall('TestCommand', Buffer.from('data'), -100)).rejects.toThrow('Nieprawidłowy timeout RPC: -100ms');
|
|
134
|
+
}));
|
|
135
|
+
it('powinien rzucić błąd przy Infinity timeout (M1)', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
136
|
+
yield expect(handler.rpcCall('TestCommand', Buffer.from('data'), Infinity)).rejects.toThrow('Nieprawidłowy timeout RPC: Infinityms');
|
|
137
|
+
}));
|
|
138
|
+
it('powinien użyć minimum 1 sekundy dla BRPOP timeout', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
139
|
+
const responseData = Buffer.from(JSON.stringify({ result: 'ok' }));
|
|
140
|
+
rpcConn.brpop.mockResolvedValue(['rpc:res:test', redis_codec_1.RedisCodec.encode(responseData)]);
|
|
141
|
+
yield handler.rpcCall('TestCommand', Buffer.from('data'), 100); // 100ms < 1s
|
|
142
|
+
// BRPOP powinien mieć timeout = 1 (minimalna wartość)
|
|
143
|
+
expect(rpcConn.brpop).toHaveBeenCalledWith(expect.stringContaining('rpc:res:'), 1);
|
|
144
|
+
}));
|
|
145
|
+
});
|
|
146
|
+
describe('rpcRespond()', () => {
|
|
147
|
+
it('powinien wysłać odpowiedź przez pipeline LPUSH + EXPIRE', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
148
|
+
const responseData = Buffer.from('response');
|
|
149
|
+
yield handler.rpcRespond('rpc:res:test-id', responseData, 60);
|
|
150
|
+
const pipeline = mockConn.pipeline();
|
|
151
|
+
expect(mockConn.pipeline).toHaveBeenCalled();
|
|
152
|
+
expect(pipeline.lpush).toHaveBeenCalledWith('rpc:res:test-id', redis_codec_1.RedisCodec.encode(responseData));
|
|
153
|
+
expect(pipeline.expire).toHaveBeenCalledWith('rpc:res:test-id', 60);
|
|
154
|
+
}));
|
|
155
|
+
});
|
|
156
|
+
});
|
|
157
|
+
//# sourceMappingURL=rpc-handler.spec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rpc-handler.spec.js","sourceRoot":"","sources":["../../../src/command-bus/transport/rpc-handler.spec.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import type { ILogger } from '../../shared/types';
|
|
2
|
+
import type { ISerializer } from '../serialization/serializer.interface';
|
|
3
|
+
import type { IStreamConsumer, ConsumerHandler } from './transport.interface';
|
|
4
|
+
import type RedisConnectionPool from '../../shared/redis/connection-pool';
|
|
5
|
+
import type { RpcResponder } from './message-processor';
|
|
6
|
+
/**
|
|
7
|
+
* Konfiguracja StreamConsumer
|
|
8
|
+
*/
|
|
9
|
+
export interface StreamConsumerOptions {
|
|
10
|
+
pool: RedisConnectionPool;
|
|
11
|
+
serializer: ISerializer;
|
|
12
|
+
logger: ILogger;
|
|
13
|
+
consumerId: string;
|
|
14
|
+
batchSize: number;
|
|
15
|
+
concurrency: number;
|
|
16
|
+
maxRetained: number;
|
|
17
|
+
rpcRespond: RpcResponder;
|
|
18
|
+
/** Próg czasu (ms) po którym wpis w processing Map jest uznawany za stale (domyślnie 300_000 = 5min) */
|
|
19
|
+
staleThreshold?: number;
|
|
20
|
+
/** Minimalny interwał (ms) między sweepami stale wpisów (domyślnie 10_000 = 10s) */
|
|
21
|
+
sweepInterval?: number;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Koordynator konsumenta strumienia Redis — komponuje MessageProcessor i ConsumerLoop
|
|
25
|
+
*
|
|
26
|
+
* Odpowiedzialności:
|
|
27
|
+
* - Zarządzanie cyklem życia: tworzenie połączeń, consumer groups, uruchamianie loops
|
|
28
|
+
* - Deduplicacja (processing Map z TTL sweep) (H1)
|
|
29
|
+
* - Koordynacja komponentów: MessageProcessor i ConsumerLoop
|
|
30
|
+
*
|
|
31
|
+
* NIE odpowiada za:
|
|
32
|
+
* - Przetwarzanie wiadomości (MessageProcessor)
|
|
33
|
+
* - Consumer loop z concurrency limiter (ConsumerLoop)
|
|
34
|
+
*/
|
|
35
|
+
export declare class StreamConsumer implements IStreamConsumer {
|
|
36
|
+
private readonly pool;
|
|
37
|
+
private readonly logger;
|
|
38
|
+
private readonly consumerId;
|
|
39
|
+
private readonly batchSize;
|
|
40
|
+
private readonly concurrency;
|
|
41
|
+
/** H1: Próg czasu (ms) po którym wpis w processing Map jest uznawany za stale */
|
|
42
|
+
private readonly staleThreshold;
|
|
43
|
+
/** Timestamp ostatniego sweep — throttle co sweepInterval */
|
|
44
|
+
private lastSweepTime;
|
|
45
|
+
/** Minimalny interwał między sweep (ms) */
|
|
46
|
+
private readonly sweepInterval;
|
|
47
|
+
/** Procesor wiadomości — parsuje, waliduje, przetwarza */
|
|
48
|
+
private readonly messageProcessor;
|
|
49
|
+
/** Instancje consumer loops — do propagacji flagi running */
|
|
50
|
+
private readonly loops;
|
|
51
|
+
/** Dedykowane połączenia konsumentów (XREADGROUP BLOCK) */
|
|
52
|
+
private readonly consumerConnections;
|
|
53
|
+
/** Promises consumer loops — do graceful shutdown */
|
|
54
|
+
private readonly consumerLoopPromises;
|
|
55
|
+
/** H1: Wiadomości aktualnie przetwarzane — Map<messageId, timestamp> z TTL sweep */
|
|
56
|
+
private readonly processing;
|
|
57
|
+
/** Flaga zatrzymania — propaguje do wszystkich consumer loops */
|
|
58
|
+
private _running;
|
|
59
|
+
get running(): boolean;
|
|
60
|
+
set running(value: boolean);
|
|
61
|
+
/** Zwraca liczbę aktywnych konsumentów (do logów) */
|
|
62
|
+
get consumerCount(): number;
|
|
63
|
+
/**
|
|
64
|
+
* Zamyka dedykowane połączenia konsumentów (przerywa XREADGROUP BLOCK)
|
|
65
|
+
*/
|
|
66
|
+
closeConnections(): void;
|
|
67
|
+
/**
|
|
68
|
+
* Czeka na zakończenie consumer loops
|
|
69
|
+
*/
|
|
70
|
+
awaitLoops(): Promise<void>;
|
|
71
|
+
constructor(options: StreamConsumerOptions);
|
|
72
|
+
/**
|
|
73
|
+
* Rejestruje konsumenta dla strumienia z consumer group
|
|
74
|
+
* Tworzy dedykowane połączenie (XREADGROUP BLOCK blokuje socket)
|
|
75
|
+
*/
|
|
76
|
+
consume(streamName: string, groupName: string, handler: ConsumerHandler): Promise<void>;
|
|
77
|
+
/**
|
|
78
|
+
* Przetwarza pojedynczą wiadomość ze strumienia
|
|
79
|
+
* Deduplicacja + delegacja do MessageProcessor
|
|
80
|
+
*
|
|
81
|
+
* Wywoływane zarówno przez ConsumerLoop (nowe wiadomości) jak i PendingRecovery (XCLAIM)
|
|
82
|
+
*/
|
|
83
|
+
processMessage(streamName: string, groupName: string, messageId: string, fields: string[], handler: ConsumerHandler): Promise<void>;
|
|
84
|
+
/**
|
|
85
|
+
* H1: Usuwa stale wpisy z processing Map — zapobiega permanentnej blokadzie recovery
|
|
86
|
+
* Wpis uznawany za stale gdy trwa dłużej niż staleThreshold
|
|
87
|
+
*/
|
|
88
|
+
private sweepStaleProcessing;
|
|
89
|
+
}
|
|
@@ -0,0 +1,181 @@
|
|
|
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.StreamConsumer = void 0;
|
|
13
|
+
const message_processor_1 = require("./message-processor");
|
|
14
|
+
const consumer_loop_1 = require("./consumer-loop");
|
|
15
|
+
const error_utils_1 = require("../../shared/utils/error-utils");
|
|
16
|
+
/**
|
|
17
|
+
* Koordynator konsumenta strumienia Redis — komponuje MessageProcessor i ConsumerLoop
|
|
18
|
+
*
|
|
19
|
+
* Odpowiedzialności:
|
|
20
|
+
* - Zarządzanie cyklem życia: tworzenie połączeń, consumer groups, uruchamianie loops
|
|
21
|
+
* - Deduplicacja (processing Map z TTL sweep) (H1)
|
|
22
|
+
* - Koordynacja komponentów: MessageProcessor i ConsumerLoop
|
|
23
|
+
*
|
|
24
|
+
* NIE odpowiada za:
|
|
25
|
+
* - Przetwarzanie wiadomości (MessageProcessor)
|
|
26
|
+
* - Consumer loop z concurrency limiter (ConsumerLoop)
|
|
27
|
+
*/
|
|
28
|
+
class StreamConsumer {
|
|
29
|
+
get running() {
|
|
30
|
+
return this._running;
|
|
31
|
+
}
|
|
32
|
+
set running(value) {
|
|
33
|
+
this._running = value;
|
|
34
|
+
for (const loop of this.loops) {
|
|
35
|
+
loop.running = value;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
/** Zwraca liczbę aktywnych konsumentów (do logów) */
|
|
39
|
+
get consumerCount() {
|
|
40
|
+
return this.consumerConnections.length;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Zamyka dedykowane połączenia konsumentów (przerywa XREADGROUP BLOCK)
|
|
44
|
+
*/
|
|
45
|
+
closeConnections() {
|
|
46
|
+
for (const conn of this.consumerConnections) {
|
|
47
|
+
conn.disconnect();
|
|
48
|
+
}
|
|
49
|
+
this.consumerConnections.length = 0;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Czeka na zakończenie consumer loops
|
|
53
|
+
*/
|
|
54
|
+
awaitLoops() {
|
|
55
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
56
|
+
if (this.consumerLoopPromises.length > 0) {
|
|
57
|
+
yield Promise.allSettled(this.consumerLoopPromises);
|
|
58
|
+
this.consumerLoopPromises.length = 0;
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
constructor(options) {
|
|
63
|
+
var _a, _b;
|
|
64
|
+
/** Timestamp ostatniego sweep — throttle co sweepInterval */
|
|
65
|
+
this.lastSweepTime = 0;
|
|
66
|
+
/** Instancje consumer loops — do propagacji flagi running */
|
|
67
|
+
this.loops = [];
|
|
68
|
+
/** Dedykowane połączenia konsumentów (XREADGROUP BLOCK) */
|
|
69
|
+
this.consumerConnections = [];
|
|
70
|
+
/** Promises consumer loops — do graceful shutdown */
|
|
71
|
+
this.consumerLoopPromises = [];
|
|
72
|
+
/** H1: Wiadomości aktualnie przetwarzane — Map<messageId, timestamp> z TTL sweep */
|
|
73
|
+
this.processing = new Map();
|
|
74
|
+
/** Flaga zatrzymania — propaguje do wszystkich consumer loops */
|
|
75
|
+
this._running = true;
|
|
76
|
+
this.pool = options.pool;
|
|
77
|
+
this.logger = options.logger;
|
|
78
|
+
this.consumerId = options.consumerId;
|
|
79
|
+
this.batchSize = options.batchSize;
|
|
80
|
+
this.concurrency = options.concurrency;
|
|
81
|
+
this.staleThreshold = (_a = options.staleThreshold) !== null && _a !== void 0 ? _a : 300000;
|
|
82
|
+
this.sweepInterval = (_b = options.sweepInterval) !== null && _b !== void 0 ? _b : 10000;
|
|
83
|
+
this.messageProcessor = new message_processor_1.MessageProcessor({
|
|
84
|
+
pool: options.pool,
|
|
85
|
+
serializer: options.serializer,
|
|
86
|
+
logger: options.logger,
|
|
87
|
+
batchSize: options.batchSize,
|
|
88
|
+
maxRetained: options.maxRetained,
|
|
89
|
+
rpcRespond: options.rpcRespond,
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Rejestruje konsumenta dla strumienia z consumer group
|
|
94
|
+
* Tworzy dedykowane połączenie (XREADGROUP BLOCK blokuje socket)
|
|
95
|
+
*/
|
|
96
|
+
consume(streamName, groupName, handler) {
|
|
97
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
98
|
+
const conn = this.pool.createDedicated(streamName);
|
|
99
|
+
this.consumerConnections.push(conn);
|
|
100
|
+
// Utwórz consumer group (ignoruj jeśli już istnieje)
|
|
101
|
+
try {
|
|
102
|
+
yield conn.xgroup('CREATE', streamName, groupName, '0', 'MKSTREAM');
|
|
103
|
+
}
|
|
104
|
+
catch (error) {
|
|
105
|
+
const msg = (0, error_utils_1.getErrorMessage)(error);
|
|
106
|
+
if (!msg.includes('BUSYGROUP')) {
|
|
107
|
+
throw error;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
// Utwórz consumer loop i uruchom w tle
|
|
111
|
+
const loop = new consumer_loop_1.ConsumerLoop({
|
|
112
|
+
consumerId: this.consumerId,
|
|
113
|
+
batchSize: this.batchSize,
|
|
114
|
+
concurrency: this.concurrency,
|
|
115
|
+
logger: this.logger,
|
|
116
|
+
});
|
|
117
|
+
this.loops.push(loop);
|
|
118
|
+
const loopPromise = loop.run(conn, streamName, groupName, (messageId, fields) => this.processMessage(streamName, groupName, messageId, fields, handler));
|
|
119
|
+
this.consumerLoopPromises.push(loopPromise);
|
|
120
|
+
this.logger.debug('Konsument zarejestrowany', {
|
|
121
|
+
streamName,
|
|
122
|
+
groupName,
|
|
123
|
+
consumerId: this.consumerId,
|
|
124
|
+
timestamp: new Date().toISOString(),
|
|
125
|
+
});
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Przetwarza pojedynczą wiadomość ze strumienia
|
|
130
|
+
* Deduplicacja + delegacja do MessageProcessor
|
|
131
|
+
*
|
|
132
|
+
* Wywoływane zarówno przez ConsumerLoop (nowe wiadomości) jak i PendingRecovery (XCLAIM)
|
|
133
|
+
*/
|
|
134
|
+
processMessage(streamName, groupName, messageId, fields, handler) {
|
|
135
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
136
|
+
// H1: Throttled sweep stale wpisów — co sweepInterval zamiast na każdą wiadomość
|
|
137
|
+
const now = Date.now();
|
|
138
|
+
if (now - this.lastSweepTime > this.sweepInterval) {
|
|
139
|
+
this.sweepStaleProcessing();
|
|
140
|
+
this.lastSweepTime = now;
|
|
141
|
+
}
|
|
142
|
+
if (this.processing.has(messageId)) {
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
this.processing.set(messageId, Date.now());
|
|
146
|
+
try {
|
|
147
|
+
yield this.messageProcessor.process(streamName, groupName, messageId, fields, handler);
|
|
148
|
+
}
|
|
149
|
+
catch (error) {
|
|
150
|
+
this.logger.error('Błąd przetwarzania wiadomości', {
|
|
151
|
+
streamName,
|
|
152
|
+
messageId,
|
|
153
|
+
error: (0, error_utils_1.getErrorMessage)(error),
|
|
154
|
+
timestamp: new Date().toISOString(),
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
finally {
|
|
158
|
+
this.processing.delete(messageId);
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* H1: Usuwa stale wpisy z processing Map — zapobiega permanentnej blokadzie recovery
|
|
164
|
+
* Wpis uznawany za stale gdy trwa dłużej niż staleThreshold
|
|
165
|
+
*/
|
|
166
|
+
sweepStaleProcessing() {
|
|
167
|
+
const now = Date.now();
|
|
168
|
+
for (const [id, timestamp] of this.processing) {
|
|
169
|
+
if (now - timestamp > this.staleThreshold) {
|
|
170
|
+
this.processing.delete(id);
|
|
171
|
+
this.logger.warn('Usunięto stale wpis z processing Map', {
|
|
172
|
+
messageId: id,
|
|
173
|
+
age: now - timestamp,
|
|
174
|
+
threshold: this.staleThreshold,
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
exports.StreamConsumer = StreamConsumer;
|
|
181
|
+
//# sourceMappingURL=stream-consumer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stream-consumer.js","sourceRoot":"","sources":["../../../src/command-bus/transport/stream-consumer.ts"],"names":[],"mappings":"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"}
|