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,176 @@
|
|
|
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 pending_recovery_1 = require("./pending-recovery");
|
|
13
|
+
/**
|
|
14
|
+
* Mock helpers
|
|
15
|
+
*/
|
|
16
|
+
function createMockLogger() {
|
|
17
|
+
return {
|
|
18
|
+
log: jest.fn(),
|
|
19
|
+
error: jest.fn(),
|
|
20
|
+
warn: jest.fn(),
|
|
21
|
+
debug: jest.fn(),
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
function createMockConnection() {
|
|
25
|
+
return {
|
|
26
|
+
xpending: jest.fn().mockResolvedValue([]),
|
|
27
|
+
xclaim: jest.fn().mockResolvedValue([]),
|
|
28
|
+
xack: jest.fn().mockResolvedValue(1),
|
|
29
|
+
xadd: jest.fn().mockResolvedValue('1700000000000-0'),
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
function createMockPool() {
|
|
33
|
+
const conn = createMockConnection();
|
|
34
|
+
return {
|
|
35
|
+
pool: { next: jest.fn().mockReturnValue(conn) },
|
|
36
|
+
conn,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
function createMockConsumer() {
|
|
40
|
+
return {
|
|
41
|
+
processMessage: jest.fn().mockResolvedValue(undefined),
|
|
42
|
+
processing: new Map(),
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
describe('PendingRecovery', () => {
|
|
46
|
+
let recovery;
|
|
47
|
+
let logger;
|
|
48
|
+
let mockConn;
|
|
49
|
+
let mockPool;
|
|
50
|
+
let mockConsumer;
|
|
51
|
+
beforeEach(() => {
|
|
52
|
+
jest.clearAllMocks();
|
|
53
|
+
jest.useFakeTimers();
|
|
54
|
+
logger = createMockLogger();
|
|
55
|
+
const poolMock = createMockPool();
|
|
56
|
+
mockPool = poolMock.pool;
|
|
57
|
+
mockConn = poolMock.conn;
|
|
58
|
+
mockConsumer = createMockConsumer();
|
|
59
|
+
recovery = new pending_recovery_1.PendingRecovery({
|
|
60
|
+
pool: mockPool,
|
|
61
|
+
logger,
|
|
62
|
+
consumerId: 'test-consumer',
|
|
63
|
+
maxAttempts: 3,
|
|
64
|
+
claimTimeout: 30000,
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
afterEach(() => {
|
|
68
|
+
recovery.stop();
|
|
69
|
+
jest.useRealTimers();
|
|
70
|
+
});
|
|
71
|
+
describe('start/stop', () => {
|
|
72
|
+
it('powinien uruchomić periodyczny recovery', () => {
|
|
73
|
+
const handler = jest.fn();
|
|
74
|
+
recovery.start('cmd:Test', 'workers', handler, mockConsumer);
|
|
75
|
+
expect(recovery['recoveryIntervals'].length).toBe(1);
|
|
76
|
+
});
|
|
77
|
+
it('powinien zatrzymać recovery intervals', () => {
|
|
78
|
+
const handler = jest.fn();
|
|
79
|
+
recovery.start('cmd:Test', 'workers', handler, mockConsumer);
|
|
80
|
+
recovery.start('cmd:Other', 'workers', handler, mockConsumer);
|
|
81
|
+
expect(recovery['recoveryIntervals'].length).toBe(2);
|
|
82
|
+
recovery.stop();
|
|
83
|
+
expect(recovery['recoveryIntervals'].length).toBe(0);
|
|
84
|
+
});
|
|
85
|
+
it('powinien wywołać recoverPending co claimTimeout', () => {
|
|
86
|
+
const handler = jest.fn();
|
|
87
|
+
recovery.start('cmd:Test', 'workers', handler, mockConsumer);
|
|
88
|
+
// Advance timer o 3 interwały
|
|
89
|
+
jest.advanceTimersByTime(90000); // 3 * 30000
|
|
90
|
+
// XPENDING powinien być wywołany 3 razy
|
|
91
|
+
expect(mockConn.xpending).toHaveBeenCalledTimes(3);
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
describe('recoverPending()', () => {
|
|
95
|
+
/**
|
|
96
|
+
* Dostęp do prywatnej metody recoverPending przez casting
|
|
97
|
+
*/
|
|
98
|
+
const callRecoverPending = () => __awaiter(void 0, void 0, void 0, function* () {
|
|
99
|
+
const any = recovery;
|
|
100
|
+
yield any['recoverPending']('cmd:Test', 'workers', jest.fn(), mockConsumer);
|
|
101
|
+
});
|
|
102
|
+
it('powinien nie robić nic gdy brak pending wiadomości', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
103
|
+
mockConn.xpending.mockResolvedValue([]);
|
|
104
|
+
yield callRecoverPending();
|
|
105
|
+
expect(mockConn.xclaim).not.toHaveBeenCalled();
|
|
106
|
+
expect(mockConn.xack).not.toHaveBeenCalled();
|
|
107
|
+
}));
|
|
108
|
+
it('powinien przejąć stalled wiadomość przez XCLAIM', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
109
|
+
const testPayload = Buffer.from('recovered-data').toString('base64');
|
|
110
|
+
mockConn.xpending.mockResolvedValue([
|
|
111
|
+
['msg-1', 'consumer-old', 60000, 1], // idleTime > claimTimeout, deliveryCount < maxAttempts
|
|
112
|
+
]);
|
|
113
|
+
mockConn.xclaim.mockResolvedValue([['msg-1', ['data', testPayload]]]);
|
|
114
|
+
yield callRecoverPending();
|
|
115
|
+
expect(mockConn.xclaim).toHaveBeenCalledWith('cmd:Test', 'workers', 'test-consumer', 30000, 'msg-1');
|
|
116
|
+
expect(mockConsumer.processMessage).toHaveBeenCalledWith('cmd:Test', 'workers', 'msg-1', ['data', testPayload], expect.any(Function));
|
|
117
|
+
}));
|
|
118
|
+
it('powinien przenieść do DLQ po maxAttempts (D3)', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
119
|
+
const testPayload = Buffer.from('dead-data').toString('base64');
|
|
120
|
+
mockConn.xpending.mockResolvedValue([
|
|
121
|
+
['msg-dead', 'consumer-old', 60000, 3], // deliveryCount >= maxAttempts
|
|
122
|
+
]);
|
|
123
|
+
// XCLAIM zwraca dane wiadomości do przeniesienia do DLQ
|
|
124
|
+
mockConn.xclaim.mockResolvedValue([['msg-dead', ['data', testPayload]]]);
|
|
125
|
+
yield callRecoverPending();
|
|
126
|
+
// XCLAIM powinien być wywołany (żeby pobrać dane do DLQ)
|
|
127
|
+
expect(mockConn.xclaim).toHaveBeenCalled();
|
|
128
|
+
// XADD do dlq: strumienia
|
|
129
|
+
expect(mockConn.xadd).toHaveBeenCalledWith('dlq:cmd:Test', '*', 'data', testPayload, 'original_stream', 'cmd:Test', 'delivery_count', '3');
|
|
130
|
+
// XACK po przeniesieniu do DLQ
|
|
131
|
+
expect(mockConn.xack).toHaveBeenCalledWith('cmd:Test', 'workers', 'msg-dead');
|
|
132
|
+
expect(logger.error).toHaveBeenCalledWith('Wiadomość przeniesiona do Dead Letter Queue', expect.objectContaining({
|
|
133
|
+
messageId: 'msg-dead',
|
|
134
|
+
dlqStream: 'dlq:cmd:Test',
|
|
135
|
+
deliveryCount: 3,
|
|
136
|
+
}));
|
|
137
|
+
}));
|
|
138
|
+
it('nie powinien przejmować wiadomości z idleTime < claimTimeout', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
139
|
+
mockConn.xpending.mockResolvedValue([
|
|
140
|
+
['msg-young', 'consumer-other', 5000, 1], // idleTime (5s) < claimTimeout (30s)
|
|
141
|
+
]);
|
|
142
|
+
yield callRecoverPending();
|
|
143
|
+
expect(mockConn.xclaim).not.toHaveBeenCalled();
|
|
144
|
+
expect(mockConn.xack).not.toHaveBeenCalled();
|
|
145
|
+
}));
|
|
146
|
+
it('powinien zalogować błąd przy wyjątku', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
147
|
+
mockConn.xpending.mockRejectedValue(new Error('Redis connection error'));
|
|
148
|
+
yield callRecoverPending();
|
|
149
|
+
expect(logger.error).toHaveBeenCalledWith('Błąd recovery pending wiadomości', expect.objectContaining({ error: 'Redis connection error' }));
|
|
150
|
+
}));
|
|
151
|
+
it('powinien obsłużyć pusty wynik XCLAIM', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
152
|
+
mockConn.xpending.mockResolvedValue([['msg-1', 'consumer-old', 60000, 1]]);
|
|
153
|
+
mockConn.xclaim.mockResolvedValue([]);
|
|
154
|
+
yield callRecoverPending();
|
|
155
|
+
// processMessage NIE powinien być wywołany (brak danych w XCLAIM)
|
|
156
|
+
expect(mockConsumer.processMessage).not.toHaveBeenCalled();
|
|
157
|
+
}));
|
|
158
|
+
it('powinien obsłużyć wiele pending wiadomości', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
159
|
+
const testPayload = Buffer.from('data').toString('base64');
|
|
160
|
+
mockConn.xpending.mockResolvedValue([
|
|
161
|
+
['msg-1', 'consumer-old', 60000, 1],
|
|
162
|
+
['msg-2', 'consumer-old', 60000, 2],
|
|
163
|
+
['msg-dead', 'consumer-old', 60000, 5], // Dead letter
|
|
164
|
+
]);
|
|
165
|
+
mockConn.xclaim.mockResolvedValue([['msg-claimed', ['data', testPayload]]]);
|
|
166
|
+
yield callRecoverPending();
|
|
167
|
+
// XCLAIM: msg-1, msg-2 (recovery) + msg-dead (DLQ pobieranie danych) = 3
|
|
168
|
+
expect(mockConn.xclaim).toHaveBeenCalledTimes(3);
|
|
169
|
+
// XADD do DLQ
|
|
170
|
+
expect(mockConn.xadd).toHaveBeenCalledWith('dlq:cmd:Test', '*', expect.anything(), expect.anything(), 'original_stream', 'cmd:Test', 'delivery_count', '5');
|
|
171
|
+
// XACK dla dead letter
|
|
172
|
+
expect(mockConn.xack).toHaveBeenCalledWith('cmd:Test', 'workers', 'msg-dead');
|
|
173
|
+
}));
|
|
174
|
+
});
|
|
175
|
+
});
|
|
176
|
+
//# sourceMappingURL=pending-recovery.spec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pending-recovery.spec.js","sourceRoot":"","sources":["../../../src/command-bus/transport/pending-recovery.spec.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Kodek Redis — enkapsulacja kodowania/dekodowania binarnych danych
|
|
3
|
+
*
|
|
4
|
+
* ioredis dekoduje string responses jako UTF-8, co korumpuje surowe bajty msgpack.
|
|
5
|
+
* Base64 zapewnia bezpieczne przechowywanie binarnych danych w Redis Streams.
|
|
6
|
+
*
|
|
7
|
+
* Warianty *Buffer() (np. xreadgroupBuffer) nie są praktyczne — zwracają Buffer
|
|
8
|
+
* dla WSZYSTKICH pól (nazwy strumieni, messageId, klucze), co komplikuje parsowanie
|
|
9
|
+
* zagnieżdżonej struktury XREADGROUP.
|
|
10
|
+
*/
|
|
11
|
+
export declare class RedisCodec {
|
|
12
|
+
/**
|
|
13
|
+
* Koduje dane binarne do bezpiecznego formatu dla Redis
|
|
14
|
+
* @param data - Surowe dane binarne
|
|
15
|
+
* @returns Zakodowany string (base64)
|
|
16
|
+
*/
|
|
17
|
+
static encode(data: Buffer): string;
|
|
18
|
+
/**
|
|
19
|
+
* Dekoduje dane z Redis do formatu binarnego
|
|
20
|
+
* @param encoded - Zakodowany string (base64)
|
|
21
|
+
* @returns Surowe dane binarne
|
|
22
|
+
*/
|
|
23
|
+
static decode(encoded: string): Buffer;
|
|
24
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.RedisCodec = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Kodek Redis — enkapsulacja kodowania/dekodowania binarnych danych
|
|
6
|
+
*
|
|
7
|
+
* ioredis dekoduje string responses jako UTF-8, co korumpuje surowe bajty msgpack.
|
|
8
|
+
* Base64 zapewnia bezpieczne przechowywanie binarnych danych w Redis Streams.
|
|
9
|
+
*
|
|
10
|
+
* Warianty *Buffer() (np. xreadgroupBuffer) nie są praktyczne — zwracają Buffer
|
|
11
|
+
* dla WSZYSTKICH pól (nazwy strumieni, messageId, klucze), co komplikuje parsowanie
|
|
12
|
+
* zagnieżdżonej struktury XREADGROUP.
|
|
13
|
+
*/
|
|
14
|
+
class RedisCodec {
|
|
15
|
+
/**
|
|
16
|
+
* Koduje dane binarne do bezpiecznego formatu dla Redis
|
|
17
|
+
* @param data - Surowe dane binarne
|
|
18
|
+
* @returns Zakodowany string (base64)
|
|
19
|
+
*/
|
|
20
|
+
static encode(data) {
|
|
21
|
+
return data.toString('base64');
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Dekoduje dane z Redis do formatu binarnego
|
|
25
|
+
* @param encoded - Zakodowany string (base64)
|
|
26
|
+
* @returns Surowe dane binarne
|
|
27
|
+
*/
|
|
28
|
+
static decode(encoded) {
|
|
29
|
+
return Buffer.from(encoded, 'base64');
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
exports.RedisCodec = RedisCodec;
|
|
33
|
+
//# sourceMappingURL=redis-codec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"redis-codec.js","sourceRoot":"","sources":["../../../src/command-bus/transport/redis-codec.ts"],"names":[],"mappings":";;;AAAA;;;;;;;;;GASG;AACH,MAAa,UAAU;IACrB;;;;OAIG;IACH,MAAM,CAAC,MAAM,CAAC,IAAY;QACxB,OAAO,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;IACjC,CAAC;IAED;;;;OAIG;IACH,MAAM,CAAC,MAAM,CAAC,OAAe;QAC3B,OAAO,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;IACxC,CAAC;CACF;AAlBD,gCAkBC"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const redis_codec_1 = require("./redis-codec");
|
|
4
|
+
describe('RedisCodec', () => {
|
|
5
|
+
describe('encode/decode roundtrip', () => {
|
|
6
|
+
it('powinien zakodować i zdekodować dane binarne bez utraty', () => {
|
|
7
|
+
const original = Buffer.from('Jan Kowalski, ul. Długa 15, Warszawa');
|
|
8
|
+
const encoded = redis_codec_1.RedisCodec.encode(original);
|
|
9
|
+
const decoded = redis_codec_1.RedisCodec.decode(encoded);
|
|
10
|
+
expect(decoded).toEqual(original);
|
|
11
|
+
});
|
|
12
|
+
it('powinien obsłużyć pusty Buffer', () => {
|
|
13
|
+
const original = Buffer.alloc(0);
|
|
14
|
+
const encoded = redis_codec_1.RedisCodec.encode(original);
|
|
15
|
+
const decoded = redis_codec_1.RedisCodec.decode(encoded);
|
|
16
|
+
expect(decoded).toEqual(original);
|
|
17
|
+
expect(decoded.length).toBe(0);
|
|
18
|
+
});
|
|
19
|
+
it('powinien obsłużyć dane binarne z null bytes', () => {
|
|
20
|
+
const original = Buffer.from([0x00, 0x01, 0xff, 0x00, 0xab]);
|
|
21
|
+
const encoded = redis_codec_1.RedisCodec.encode(original);
|
|
22
|
+
const decoded = redis_codec_1.RedisCodec.decode(encoded);
|
|
23
|
+
expect(decoded).toEqual(original);
|
|
24
|
+
});
|
|
25
|
+
it('powinien obsłużyć duże dane (1MB)', () => {
|
|
26
|
+
const original = Buffer.alloc(1024 * 1024, 0xab);
|
|
27
|
+
const encoded = redis_codec_1.RedisCodec.encode(original);
|
|
28
|
+
const decoded = redis_codec_1.RedisCodec.decode(encoded);
|
|
29
|
+
expect(decoded).toEqual(original);
|
|
30
|
+
});
|
|
31
|
+
});
|
|
32
|
+
describe('encode()', () => {
|
|
33
|
+
it('powinien zwrócić string base64', () => {
|
|
34
|
+
const data = Buffer.from('test');
|
|
35
|
+
const encoded = redis_codec_1.RedisCodec.encode(data);
|
|
36
|
+
expect(typeof encoded).toBe('string');
|
|
37
|
+
// Walidacja formatu base64
|
|
38
|
+
expect(encoded).toMatch(/^[A-Za-z0-9+/]*={0,2}$/);
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
describe('decode()', () => {
|
|
42
|
+
it('powinien zdekodować prawidłowy base64 string', () => {
|
|
43
|
+
const base64 = Buffer.from('Anna Nowak').toString('base64');
|
|
44
|
+
const decoded = redis_codec_1.RedisCodec.decode(base64);
|
|
45
|
+
expect(decoded.toString()).toBe('Anna Nowak');
|
|
46
|
+
});
|
|
47
|
+
it('powinien zwrócić pusty Buffer dla pustego stringa', () => {
|
|
48
|
+
const decoded = redis_codec_1.RedisCodec.decode('');
|
|
49
|
+
expect(decoded.length).toBe(0);
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
//# sourceMappingURL=redis-codec.spec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"redis-codec.spec.js","sourceRoot":"","sources":["../../../src/command-bus/transport/redis-codec.spec.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import type { ILogger } from '../../shared/types';
|
|
2
|
+
import type { ISerializer } from '../serialization/serializer.interface';
|
|
3
|
+
import type { ITransport, ConsumerHandler } from './transport.interface';
|
|
4
|
+
import type RedisConnectionPool from '../../shared/redis/connection-pool';
|
|
5
|
+
import type RpcConnectionPool from '../../shared/redis/rpc-connection-pool';
|
|
6
|
+
import type { ICommandInterceptor } from '../interceptors';
|
|
7
|
+
/**
|
|
8
|
+
* Opcje konfiguracji RedisStreamsTransport
|
|
9
|
+
*/
|
|
10
|
+
export interface RedisStreamsTransportOptions {
|
|
11
|
+
/** Pula połączeń Redis (round-robin, non-blocking ops) */
|
|
12
|
+
pool: RedisConnectionPool;
|
|
13
|
+
/** Pula połączeń RPC (bounded, lazy, blocking BRPOP) */
|
|
14
|
+
rpcPool: RpcConnectionPool;
|
|
15
|
+
/** Serializer do konwersji RPC metadata */
|
|
16
|
+
serializer: ISerializer;
|
|
17
|
+
/** Logger */
|
|
18
|
+
logger: ILogger;
|
|
19
|
+
/** Maksymalna liczba wiadomości w strumieniu (XTRIM ~) */
|
|
20
|
+
maxRetained: number;
|
|
21
|
+
/** Maksymalna liczba prób przetworzenia wiadomości */
|
|
22
|
+
maxAttempts: number;
|
|
23
|
+
/** Czas po którym stalled wiadomość jest przejmowana (ms) */
|
|
24
|
+
claimTimeout: number;
|
|
25
|
+
/** Liczba wiadomości pobieranych w jednym XREADGROUP */
|
|
26
|
+
batchSize: number;
|
|
27
|
+
/** Maksymalna liczba wiadomości przetwarzanych równolegle per konsument */
|
|
28
|
+
concurrency: number;
|
|
29
|
+
/** Interceptor przechwytujący wykonanie handlera */
|
|
30
|
+
interceptor?: ICommandInterceptor;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Fasada transportu Redis Streams dla CommandBus
|
|
34
|
+
*
|
|
35
|
+
* Kompozycja 4 komponentów z jasno rozdzielonymi odpowiedzialnościami:
|
|
36
|
+
* - StreamProducer: enqueue / enqueueBatch (XADD)
|
|
37
|
+
* - StreamConsumer: consume / consumerLoop / processMessage
|
|
38
|
+
* - RpcHandler: rpcCall / rpcRespond (LPUSH/BRPOP)
|
|
39
|
+
* - PendingRecovery: XPENDING / XCLAIM / dead letter
|
|
40
|
+
*
|
|
41
|
+
* Zachowuje publiczne API ITransport — zero zmian dla CommandBus
|
|
42
|
+
*/
|
|
43
|
+
export default class RedisStreamsTransport implements ITransport {
|
|
44
|
+
private readonly pool;
|
|
45
|
+
private readonly rpcPool;
|
|
46
|
+
private readonly logger;
|
|
47
|
+
/** Komponenty fasady */
|
|
48
|
+
private readonly producer;
|
|
49
|
+
private readonly consumer;
|
|
50
|
+
private readonly rpc;
|
|
51
|
+
private readonly recovery;
|
|
52
|
+
/** Identyfikator procesu (dla consumer name) */
|
|
53
|
+
private readonly consumerId;
|
|
54
|
+
constructor(options: RedisStreamsTransportOptions);
|
|
55
|
+
/**
|
|
56
|
+
* Dodaje komendę do strumienia (fire-and-forget)
|
|
57
|
+
* Deleguje do StreamProducer
|
|
58
|
+
*/
|
|
59
|
+
enqueue(streamName: string, data: Buffer): Promise<string>;
|
|
60
|
+
/**
|
|
61
|
+
* Dodaje wiele komend w jednym pipeline
|
|
62
|
+
* Deleguje do StreamProducer
|
|
63
|
+
*/
|
|
64
|
+
enqueueBatch(entries: Array<{
|
|
65
|
+
streamName: string;
|
|
66
|
+
data: Buffer;
|
|
67
|
+
}>): Promise<string[]>;
|
|
68
|
+
/**
|
|
69
|
+
* Rejestruje konsumenta dla strumienia z consumer group
|
|
70
|
+
* Deleguje do StreamConsumer + uruchamia PendingRecovery
|
|
71
|
+
*/
|
|
72
|
+
consume(streamName: string, groupName: string, handler: ConsumerHandler): Promise<void>;
|
|
73
|
+
/**
|
|
74
|
+
* RPC: wysyła request do strumienia i czeka na odpowiedź via BRPOP
|
|
75
|
+
* Deleguje do RpcHandler
|
|
76
|
+
*/
|
|
77
|
+
rpcCall(commandName: string, data: Buffer, timeout: number): Promise<Buffer>;
|
|
78
|
+
/**
|
|
79
|
+
* RPC: odpowiada na request przez LPUSH + EXPIRE
|
|
80
|
+
* Deleguje do RpcHandler
|
|
81
|
+
*/
|
|
82
|
+
rpcRespond(responseKey: string, data: Buffer, ttl: number): Promise<void>;
|
|
83
|
+
/**
|
|
84
|
+
* Zamyka transport gracefully
|
|
85
|
+
*
|
|
86
|
+
* Kolejność:
|
|
87
|
+
* 1. Zatrzymaj consumer.running (przerywa consumer loops)
|
|
88
|
+
* 2. Zatrzymaj recovery intervals
|
|
89
|
+
* 3. Zamknij dedykowane połączenia konsumentów (przerywa XREADGROUP BLOCK)
|
|
90
|
+
* 4. Czekaj na zakończenie consumer loops (active tasks kończą processMessage)
|
|
91
|
+
* 5. Zamknij pule połączeń
|
|
92
|
+
*/
|
|
93
|
+
close(): Promise<void>;
|
|
94
|
+
}
|
|
@@ -0,0 +1,143 @@
|
|
|
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
|
+
interceptor: options.interceptor,
|
|
47
|
+
});
|
|
48
|
+
this.recovery = new pending_recovery_1.PendingRecovery({
|
|
49
|
+
pool: options.pool,
|
|
50
|
+
logger: options.logger,
|
|
51
|
+
consumerId: this.consumerId,
|
|
52
|
+
maxAttempts: options.maxAttempts,
|
|
53
|
+
claimTimeout: options.claimTimeout,
|
|
54
|
+
});
|
|
55
|
+
// Log inicjalizacji transportu
|
|
56
|
+
this.logger.log('Transport Redis Streams zainicjalizowany', {
|
|
57
|
+
consumerId: this.consumerId,
|
|
58
|
+
poolSize: options.pool.size,
|
|
59
|
+
maxRetained: options.maxRetained,
|
|
60
|
+
concurrency: options.concurrency,
|
|
61
|
+
timestamp: new Date().toISOString(),
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Dodaje komendę do strumienia (fire-and-forget)
|
|
66
|
+
* Deleguje do StreamProducer
|
|
67
|
+
*/
|
|
68
|
+
enqueue(streamName, data) {
|
|
69
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
70
|
+
return this.producer.enqueue(streamName, data);
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Dodaje wiele komend w jednym pipeline
|
|
75
|
+
* Deleguje do StreamProducer
|
|
76
|
+
*/
|
|
77
|
+
enqueueBatch(entries) {
|
|
78
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
79
|
+
return this.producer.enqueueBatch(entries);
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Rejestruje konsumenta dla strumienia z consumer group
|
|
84
|
+
* Deleguje do StreamConsumer + uruchamia PendingRecovery
|
|
85
|
+
*/
|
|
86
|
+
consume(streamName, groupName, handler) {
|
|
87
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
88
|
+
yield this.consumer.consume(streamName, groupName, handler);
|
|
89
|
+
// Uruchom recovery loop dla pending wiadomości
|
|
90
|
+
this.recovery.start(streamName, groupName, handler, this.consumer);
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* RPC: wysyła request do strumienia i czeka na odpowiedź via BRPOP
|
|
95
|
+
* Deleguje do RpcHandler
|
|
96
|
+
*/
|
|
97
|
+
rpcCall(commandName, data, timeout) {
|
|
98
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
99
|
+
return this.rpc.rpcCall(commandName, data, timeout);
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* RPC: odpowiada na request przez LPUSH + EXPIRE
|
|
104
|
+
* Deleguje do RpcHandler
|
|
105
|
+
*/
|
|
106
|
+
rpcRespond(responseKey, data, ttl) {
|
|
107
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
108
|
+
return this.rpc.rpcRespond(responseKey, data, ttl);
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Zamyka transport gracefully
|
|
113
|
+
*
|
|
114
|
+
* Kolejność:
|
|
115
|
+
* 1. Zatrzymaj consumer.running (przerywa consumer loops)
|
|
116
|
+
* 2. Zatrzymaj recovery intervals
|
|
117
|
+
* 3. Zamknij dedykowane połączenia konsumentów (przerywa XREADGROUP BLOCK)
|
|
118
|
+
* 4. Czekaj na zakończenie consumer loops (active tasks kończą processMessage)
|
|
119
|
+
* 5. Zamknij pule połączeń
|
|
120
|
+
*/
|
|
121
|
+
close() {
|
|
122
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
123
|
+
if (!this.consumer.running)
|
|
124
|
+
return;
|
|
125
|
+
this.consumer.running = false;
|
|
126
|
+
this.logger.debug('Zamykanie RedisStreamsTransport', {
|
|
127
|
+
consumers: this.consumer.consumerCount,
|
|
128
|
+
timestamp: new Date().toISOString(),
|
|
129
|
+
});
|
|
130
|
+
// 1. Zatrzymaj recovery intervals
|
|
131
|
+
this.recovery.stop();
|
|
132
|
+
// 2. Zamknij dedykowane połączenia konsumentów — przerywa XREADGROUP BLOCK
|
|
133
|
+
this.consumer.closeConnections();
|
|
134
|
+
// 3. Czekaj na zakończenie consumer loops (active tasks kończą processMessage)
|
|
135
|
+
yield this.consumer.awaitLoops();
|
|
136
|
+
// 4. Zamknij pule połączeń — dopiero po zakończeniu wszystkich active tasks
|
|
137
|
+
yield this.pool.close();
|
|
138
|
+
yield this.rpcPool.close();
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
exports.default = RedisStreamsTransport;
|
|
143
|
+
//# 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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"}
|