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.
Files changed (195) hide show
  1. package/README.md +402 -1113
  2. package/dist/command-bus/command-bus.spec.js +144 -370
  3. package/dist/command-bus/command-bus.spec.js.map +1 -1
  4. package/dist/command-bus/command.d.ts +23 -5
  5. package/dist/command-bus/command.js +20 -34
  6. package/dist/command-bus/command.js.map +1 -1
  7. package/dist/command-bus/config/command-bus-config.d.ts +75 -21
  8. package/dist/command-bus/config/command-bus-config.js +99 -58
  9. package/dist/command-bus/config/command-bus-config.js.map +1 -1
  10. package/dist/command-bus/config/command-bus-config.spec.js +174 -100
  11. package/dist/command-bus/config/command-bus-config.spec.js.map +1 -1
  12. package/dist/command-bus/index.d.ts +39 -52
  13. package/dist/command-bus/index.js +133 -126
  14. package/dist/command-bus/index.js.map +1 -1
  15. package/dist/command-bus/logging/command-logger.d.ts +2 -0
  16. package/dist/command-bus/logging/command-logger.js +7 -0
  17. package/dist/command-bus/logging/command-logger.js.map +1 -1
  18. package/dist/command-bus/logging/command-logger.spec.js +49 -14
  19. package/dist/command-bus/logging/command-logger.spec.js.map +1 -1
  20. package/dist/command-bus/serialization/index.d.ts +6 -0
  21. package/dist/command-bus/serialization/index.js +9 -0
  22. package/dist/command-bus/serialization/index.js.map +1 -0
  23. package/dist/command-bus/serialization/msgpack-serializer.d.ts +26 -0
  24. package/dist/command-bus/serialization/msgpack-serializer.js +70 -0
  25. package/dist/command-bus/serialization/msgpack-serializer.js.map +1 -0
  26. package/dist/command-bus/serialization/msgpack-serializer.spec.js +223 -0
  27. package/dist/command-bus/serialization/msgpack-serializer.spec.js.map +1 -0
  28. package/dist/command-bus/serialization/serializer.interface.d.ts +21 -0
  29. package/dist/command-bus/serialization/serializer.interface.js +3 -0
  30. package/dist/command-bus/serialization/serializer.interface.js.map +1 -0
  31. package/dist/command-bus/transport/consumer-loop.d.ts +45 -0
  32. package/dist/command-bus/transport/consumer-loop.js +90 -0
  33. package/dist/command-bus/transport/consumer-loop.js.map +1 -0
  34. package/dist/command-bus/transport/consumer-loop.spec.js +216 -0
  35. package/dist/command-bus/transport/consumer-loop.spec.js.map +1 -0
  36. package/dist/command-bus/transport/index.d.ts +21 -0
  37. package/dist/command-bus/transport/index.js +23 -0
  38. package/dist/command-bus/transport/index.js.map +1 -0
  39. package/dist/command-bus/transport/message-processor.d.ts +59 -0
  40. package/dist/command-bus/transport/message-processor.js +111 -0
  41. package/dist/command-bus/transport/message-processor.js.map +1 -0
  42. package/dist/command-bus/transport/message-processor.spec.js +185 -0
  43. package/dist/command-bus/transport/message-processor.spec.js.map +1 -0
  44. package/dist/command-bus/transport/pending-recovery.d.ts +54 -0
  45. package/dist/command-bus/transport/pending-recovery.js +139 -0
  46. package/dist/command-bus/transport/pending-recovery.js.map +1 -0
  47. package/dist/command-bus/transport/pending-recovery.spec.js +176 -0
  48. package/dist/command-bus/transport/pending-recovery.spec.js.map +1 -0
  49. package/dist/command-bus/transport/redis-codec.d.ts +24 -0
  50. package/dist/command-bus/transport/redis-codec.js +33 -0
  51. package/dist/command-bus/transport/redis-codec.js.map +1 -0
  52. package/dist/command-bus/transport/redis-codec.spec.js +53 -0
  53. package/dist/command-bus/transport/redis-codec.spec.js.map +1 -0
  54. package/dist/command-bus/transport/redis-streams-transport.d.ts +91 -0
  55. package/dist/command-bus/transport/redis-streams-transport.js +134 -0
  56. package/dist/command-bus/transport/redis-streams-transport.js.map +1 -0
  57. package/dist/command-bus/transport/redis-streams-transport.spec.js +420 -0
  58. package/dist/command-bus/transport/redis-streams-transport.spec.js.map +1 -0
  59. package/dist/command-bus/transport/rpc-handler.d.ts +39 -0
  60. package/dist/command-bus/transport/rpc-handler.js +87 -0
  61. package/dist/command-bus/transport/rpc-handler.js.map +1 -0
  62. package/dist/command-bus/transport/rpc-handler.spec.js +157 -0
  63. package/dist/command-bus/transport/rpc-handler.spec.js.map +1 -0
  64. package/dist/command-bus/transport/stream-consumer.d.ts +89 -0
  65. package/dist/command-bus/transport/stream-consumer.js +181 -0
  66. package/dist/command-bus/transport/stream-consumer.js.map +1 -0
  67. package/dist/command-bus/transport/stream-consumer.spec.js +284 -0
  68. package/dist/command-bus/transport/stream-consumer.spec.js.map +1 -0
  69. package/dist/command-bus/transport/stream-producer.d.ts +23 -0
  70. package/dist/command-bus/transport/stream-producer.js +70 -0
  71. package/dist/command-bus/transport/stream-producer.js.map +1 -0
  72. package/dist/command-bus/transport/stream-producer.spec.js +125 -0
  73. package/dist/command-bus/transport/stream-producer.spec.js.map +1 -0
  74. package/dist/command-bus/transport/transport.interface.d.ts +87 -0
  75. package/dist/command-bus/transport/transport.interface.js +3 -0
  76. package/dist/command-bus/transport/transport.interface.js.map +1 -0
  77. package/dist/command-bus/types/index.d.ts +9 -80
  78. package/dist/examples/rpc-throughput.demo.js +24 -22
  79. package/dist/examples/rpc-throughput.demo.js.map +1 -1
  80. package/dist/examples/rpc.demo.js +47 -53
  81. package/dist/examples/rpc.demo.js.map +1 -1
  82. package/dist/index.d.ts +8 -5
  83. package/dist/index.js +6 -4
  84. package/dist/index.js.map +1 -1
  85. package/dist/pp-command-bus-2.0.0.tgz +0 -0
  86. package/dist/shared/redis/connection-pool.d.ts +54 -0
  87. package/dist/shared/redis/connection-pool.js +117 -0
  88. package/dist/shared/redis/connection-pool.js.map +1 -0
  89. package/dist/shared/redis/connection-pool.spec.js +114 -0
  90. package/dist/shared/redis/connection-pool.spec.js.map +1 -0
  91. package/dist/shared/redis/index.d.ts +5 -3
  92. package/dist/shared/redis/index.js +6 -4
  93. package/dist/shared/redis/index.js.map +1 -1
  94. package/dist/shared/redis/rpc-connection-pool.d.ts +61 -0
  95. package/dist/shared/redis/rpc-connection-pool.js +154 -0
  96. package/dist/shared/redis/rpc-connection-pool.js.map +1 -0
  97. package/dist/shared/redis/rpc-connection-pool.spec.d.ts +1 -0
  98. package/dist/shared/redis/rpc-connection-pool.spec.js +173 -0
  99. package/dist/shared/redis/rpc-connection-pool.spec.js.map +1 -0
  100. package/dist/shared/types.d.ts +0 -4
  101. package/dist/shared/utils/error-utils.d.ts +8 -0
  102. package/dist/shared/utils/error-utils.js +14 -0
  103. package/dist/shared/utils/error-utils.js.map +1 -0
  104. package/package.json +12 -12
  105. package/dist/command-bus/config/auto-config-optimizer.d.ts +0 -35
  106. package/dist/command-bus/config/auto-config-optimizer.js +0 -52
  107. package/dist/command-bus/config/auto-config-optimizer.js.map +0 -1
  108. package/dist/command-bus/config/auto-config-optimizer.spec.js +0 -42
  109. package/dist/command-bus/config/auto-config-optimizer.spec.js.map +0 -1
  110. package/dist/command-bus/job/index.d.ts +0 -6
  111. package/dist/command-bus/job/index.js +0 -15
  112. package/dist/command-bus/job/index.js.map +0 -1
  113. package/dist/command-bus/job/job-options-builder.d.ts +0 -21
  114. package/dist/command-bus/job/job-options-builder.js +0 -58
  115. package/dist/command-bus/job/job-options-builder.js.map +0 -1
  116. package/dist/command-bus/job/job-options-builder.spec.js +0 -156
  117. package/dist/command-bus/job/job-options-builder.spec.js.map +0 -1
  118. package/dist/command-bus/job/job-processor.d.ts +0 -39
  119. package/dist/command-bus/job/job-processor.js +0 -203
  120. package/dist/command-bus/job/job-processor.js.map +0 -1
  121. package/dist/command-bus/job/job-processor.spec.js +0 -437
  122. package/dist/command-bus/job/job-processor.spec.js.map +0 -1
  123. package/dist/command-bus/queue/index.d.ts +0 -5
  124. package/dist/command-bus/queue/index.js +0 -13
  125. package/dist/command-bus/queue/index.js.map +0 -1
  126. package/dist/command-bus/queue/queue-manager.d.ts +0 -56
  127. package/dist/command-bus/queue/queue-manager.js +0 -163
  128. package/dist/command-bus/queue/queue-manager.js.map +0 -1
  129. package/dist/command-bus/queue/queue-manager.spec.js +0 -371
  130. package/dist/command-bus/queue/queue-manager.spec.js.map +0 -1
  131. package/dist/command-bus/rpc/index.d.ts +0 -11
  132. package/dist/command-bus/rpc/index.js +0 -19
  133. package/dist/command-bus/rpc/index.js.map +0 -1
  134. package/dist/command-bus/rpc/payload-compression.service.d.ts +0 -51
  135. package/dist/command-bus/rpc/payload-compression.service.js +0 -218
  136. package/dist/command-bus/rpc/payload-compression.service.js.map +0 -1
  137. package/dist/command-bus/rpc/payload-compression.service.spec.js +0 -379
  138. package/dist/command-bus/rpc/payload-compression.service.spec.js.map +0 -1
  139. package/dist/command-bus/rpc/rpc-coordinator.d.ts +0 -96
  140. package/dist/command-bus/rpc/rpc-coordinator.js +0 -500
  141. package/dist/command-bus/rpc/rpc-coordinator.js.map +0 -1
  142. package/dist/command-bus/rpc/rpc-coordinator.spec.js +0 -622
  143. package/dist/command-bus/rpc/rpc-coordinator.spec.js.map +0 -1
  144. package/dist/command-bus/rpc/rpc-job-cancellation.service.d.ts +0 -82
  145. package/dist/command-bus/rpc/rpc-job-cancellation.service.js +0 -180
  146. package/dist/command-bus/rpc/rpc-job-cancellation.service.js.map +0 -1
  147. package/dist/command-bus/rpc/rpc-job-cancellation.service.spec.js +0 -286
  148. package/dist/command-bus/rpc/rpc-job-cancellation.service.spec.js.map +0 -1
  149. package/dist/command-bus/worker/index.d.ts +0 -10
  150. package/dist/command-bus/worker/index.js +0 -19
  151. package/dist/command-bus/worker/index.js.map +0 -1
  152. package/dist/command-bus/worker/worker-benchmark.d.ts +0 -71
  153. package/dist/command-bus/worker/worker-benchmark.js +0 -203
  154. package/dist/command-bus/worker/worker-benchmark.js.map +0 -1
  155. package/dist/command-bus/worker/worker-benchmark.spec.js +0 -310
  156. package/dist/command-bus/worker/worker-benchmark.spec.js.map +0 -1
  157. package/dist/command-bus/worker/worker-metrics-collector.d.ts +0 -98
  158. package/dist/command-bus/worker/worker-metrics-collector.js +0 -242
  159. package/dist/command-bus/worker/worker-metrics-collector.js.map +0 -1
  160. package/dist/command-bus/worker/worker-orchestrator.d.ts +0 -70
  161. package/dist/command-bus/worker/worker-orchestrator.js +0 -339
  162. package/dist/command-bus/worker/worker-orchestrator.js.map +0 -1
  163. package/dist/command-bus/worker/worker-orchestrator.spec.js +0 -712
  164. package/dist/command-bus/worker/worker-orchestrator.spec.js.map +0 -1
  165. package/dist/examples/auto-config.demo.d.ts +0 -9
  166. package/dist/examples/auto-config.demo.js +0 -106
  167. package/dist/examples/auto-config.demo.js.map +0 -1
  168. package/dist/examples/rpc-compression.demo.d.ts +0 -5
  169. package/dist/examples/rpc-compression.demo.js +0 -363
  170. package/dist/examples/rpc-compression.demo.js.map +0 -1
  171. package/dist/examples/rpc-resilience.demo.d.ts +0 -11
  172. package/dist/examples/rpc-resilience.demo.js +0 -235
  173. package/dist/examples/rpc-resilience.demo.js.map +0 -1
  174. package/dist/pp-command-bus-1.4.0.tgz +0 -0
  175. package/dist/shared/config/base-config.d.ts +0 -54
  176. package/dist/shared/config/base-config.js +0 -114
  177. package/dist/shared/config/base-config.js.map +0 -1
  178. package/dist/shared/config/base-config.spec.js +0 -204
  179. package/dist/shared/config/base-config.spec.js.map +0 -1
  180. package/dist/shared/config/index.d.ts +0 -1
  181. package/dist/shared/config/index.js +0 -9
  182. package/dist/shared/config/index.js.map +0 -1
  183. package/dist/shared/redis/redis-connection-factory.d.ts +0 -66
  184. package/dist/shared/redis/redis-connection-factory.js +0 -113
  185. package/dist/shared/redis/redis-connection-factory.js.map +0 -1
  186. /package/dist/command-bus/{config/auto-config-optimizer.spec.d.ts → serialization/msgpack-serializer.spec.d.ts} +0 -0
  187. /package/dist/command-bus/{job/job-options-builder.spec.d.ts → transport/consumer-loop.spec.d.ts} +0 -0
  188. /package/dist/command-bus/{job/job-processor.spec.d.ts → transport/message-processor.spec.d.ts} +0 -0
  189. /package/dist/command-bus/{queue/queue-manager.spec.d.ts → transport/pending-recovery.spec.d.ts} +0 -0
  190. /package/dist/command-bus/{rpc/payload-compression.service.spec.d.ts → transport/redis-codec.spec.d.ts} +0 -0
  191. /package/dist/command-bus/{rpc/rpc-coordinator.spec.d.ts → transport/redis-streams-transport.spec.d.ts} +0 -0
  192. /package/dist/command-bus/{rpc/rpc-job-cancellation.service.spec.d.ts → transport/rpc-handler.spec.d.ts} +0 -0
  193. /package/dist/command-bus/{worker/worker-benchmark.spec.d.ts → transport/stream-consumer.spec.d.ts} +0 -0
  194. /package/dist/command-bus/{worker/worker-orchestrator.spec.d.ts → transport/stream-producer.spec.d.ts} +0 -0
  195. /package/dist/shared/{config/base-config.spec.d.ts → redis/connection-pool.spec.d.ts} +0 -0
@@ -0,0 +1,216 @@
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 consumer_loop_1 = require("./consumer-loop");
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
+ /**
25
+ * Tworzy mock Redis connection z disconnect() który przerywa blocking operations
26
+ */
27
+ function createMockConnection() {
28
+ const pendingRejects = [];
29
+ return {
30
+ xreadgroup: jest.fn().mockImplementation(() => new Promise((_resolve, reject) => {
31
+ pendingRejects.push(reject);
32
+ })),
33
+ disconnect: jest.fn().mockImplementation(() => {
34
+ const disconnectError = new Error('Connection is closed.');
35
+ while (pendingRejects.length > 0) {
36
+ const reject = pendingRejects.shift();
37
+ if (reject)
38
+ reject(disconnectError);
39
+ }
40
+ }),
41
+ _pendingRejects: pendingRejects,
42
+ };
43
+ }
44
+ describe('ConsumerLoop', () => {
45
+ let loop;
46
+ let logger;
47
+ beforeEach(() => {
48
+ jest.clearAllMocks();
49
+ logger = createMockLogger();
50
+ loop = new consumer_loop_1.ConsumerLoop({
51
+ consumerId: 'test-consumer',
52
+ batchSize: 10,
53
+ concurrency: 5,
54
+ logger,
55
+ });
56
+ });
57
+ afterEach(() => {
58
+ loop.running = false;
59
+ });
60
+ describe('run()', () => {
61
+ it('powinien wywołać XREADGROUP z prawidłowymi parametrami', () => __awaiter(void 0, void 0, void 0, function* () {
62
+ const conn = createMockConnection();
63
+ const onMessage = jest.fn().mockResolvedValue(undefined);
64
+ // XREADGROUP zwraca jedną wiadomość, potem blocking
65
+ conn.xreadgroup.mockResolvedValueOnce([['cmd:Test', [['msg-1', ['data', 'payload']]]]]);
66
+ const runPromise = loop.run(conn, 'cmd:Test', 'workers', onMessage);
67
+ // Poczekaj na przetworzenie pierwszej wiadomości
68
+ yield new Promise((r) => setTimeout(r, 10));
69
+ // Zatrzymaj loop
70
+ loop.running = false;
71
+ conn.disconnect();
72
+ yield runPromise;
73
+ expect(conn.xreadgroup).toHaveBeenCalledWith('GROUP', 'workers', 'test-consumer', 'COUNT', expect.any(Number), 'BLOCK', 5000, 'STREAMS', 'cmd:Test', '>');
74
+ }));
75
+ it('powinien wywołać onMessage dla każdej wiadomości', () => __awaiter(void 0, void 0, void 0, function* () {
76
+ const conn = createMockConnection();
77
+ const onMessage = jest.fn().mockResolvedValue(undefined);
78
+ conn.xreadgroup.mockResolvedValueOnce([
79
+ [
80
+ 'cmd:Test',
81
+ [
82
+ ['msg-1', ['data', 'payload1']],
83
+ ['msg-2', ['data', 'payload2']],
84
+ ],
85
+ ],
86
+ ]);
87
+ const runPromise = loop.run(conn, 'cmd:Test', 'workers', onMessage);
88
+ yield new Promise((r) => setTimeout(r, 10));
89
+ loop.running = false;
90
+ conn.disconnect();
91
+ yield runPromise;
92
+ expect(onMessage).toHaveBeenCalledTimes(2);
93
+ expect(onMessage).toHaveBeenCalledWith('msg-1', ['data', 'payload1']);
94
+ expect(onMessage).toHaveBeenCalledWith('msg-2', ['data', 'payload2']);
95
+ }));
96
+ it('powinien zakończyć gracefully gdy running = false', () => __awaiter(void 0, void 0, void 0, function* () {
97
+ const conn = createMockConnection();
98
+ const onMessage = jest.fn().mockResolvedValue(undefined);
99
+ loop.running = false;
100
+ const runPromise = loop.run(conn, 'cmd:Test', 'workers', onMessage);
101
+ yield runPromise;
102
+ expect(onMessage).not.toHaveBeenCalled();
103
+ }));
104
+ it('powinien czekać na aktywne zadania przy shutdown', () => __awaiter(void 0, void 0, void 0, function* () {
105
+ const conn = createMockConnection();
106
+ let handlerResolve;
107
+ const handlerPromise = new Promise((resolve) => {
108
+ handlerResolve = resolve;
109
+ });
110
+ const onMessage = jest.fn().mockReturnValueOnce(handlerPromise);
111
+ conn.xreadgroup.mockResolvedValueOnce([['cmd:Test', [['msg-1', ['data', 'payload']]]]]);
112
+ const runPromise = loop.run(conn, 'cmd:Test', 'workers', onMessage);
113
+ // Poczekaj na start przetwarzania
114
+ yield new Promise((r) => setTimeout(r, 10));
115
+ // Zatrzymaj loop (ale handler jeszcze pracuje)
116
+ loop.running = false;
117
+ conn.disconnect();
118
+ // Handler jeszcze nie zakończony — run() powinno czekać
119
+ const raceResult = yield Promise.race([
120
+ runPromise.then(() => 'finished'),
121
+ new Promise((r) => setTimeout(r, 50)).then(() => 'timeout'),
122
+ ]);
123
+ expect(raceResult).toBe('timeout');
124
+ // Zakończ handler
125
+ handlerResolve();
126
+ yield runPromise;
127
+ }));
128
+ it('powinien zalogować błąd i kontynuować po błędzie XREADGROUP', () => __awaiter(void 0, void 0, void 0, function* () {
129
+ jest.useFakeTimers();
130
+ const conn = createMockConnection();
131
+ const onMessage = jest.fn().mockResolvedValue(undefined);
132
+ // Pierwszy call — error, drugi — null (timeout), trzeci — zatrzymujemy
133
+ conn.xreadgroup.mockRejectedValueOnce(new Error('Redis error')).mockResolvedValueOnce(null);
134
+ const runPromise = loop.run(conn, 'cmd:Test', 'workers', onMessage);
135
+ // Advance timer past backoff
136
+ yield jest.advanceTimersByTimeAsync(2000);
137
+ // Zatrzymaj loop
138
+ loop.running = false;
139
+ conn.disconnect();
140
+ yield jest.advanceTimersByTimeAsync(1000);
141
+ yield runPromise;
142
+ expect(logger.error).toHaveBeenCalledWith('Błąd w consumer loop', expect.objectContaining({
143
+ error: 'Redis error',
144
+ consecutiveErrors: 1,
145
+ }));
146
+ jest.useRealTimers();
147
+ }));
148
+ it('powinien stosować exponential backoff przy kolejnych błędach', () => __awaiter(void 0, void 0, void 0, function* () {
149
+ jest.useFakeTimers();
150
+ const conn = createMockConnection();
151
+ const onMessage = jest.fn().mockResolvedValue(undefined);
152
+ // 3 kolejne błędy
153
+ conn.xreadgroup
154
+ .mockRejectedValueOnce(new Error('error 1'))
155
+ .mockRejectedValueOnce(new Error('error 2'))
156
+ .mockRejectedValueOnce(new Error('error 3'));
157
+ const runPromise = loop.run(conn, 'cmd:Test', 'workers', onMessage);
158
+ // Advance past first backoff (~1s + jitter)
159
+ yield jest.advanceTimersByTimeAsync(2500);
160
+ // Advance past second backoff (~2s + jitter)
161
+ yield jest.advanceTimersByTimeAsync(3500);
162
+ // Advance past third backoff (~4s + jitter)
163
+ yield jest.advanceTimersByTimeAsync(5500);
164
+ loop.running = false;
165
+ conn.disconnect();
166
+ yield jest.advanceTimersByTimeAsync(1000);
167
+ yield runPromise;
168
+ expect(logger.error).toHaveBeenCalledTimes(3);
169
+ jest.useRealTimers();
170
+ }));
171
+ it('powinien zakończyć od razu przy błędzie gdy running = false', () => __awaiter(void 0, void 0, void 0, function* () {
172
+ const conn = createMockConnection();
173
+ const onMessage = jest.fn().mockResolvedValue(undefined);
174
+ // Symuluj disconnect error
175
+ conn.xreadgroup.mockRejectedValueOnce(new Error('Connection is closed.'));
176
+ loop.running = false;
177
+ const runPromise = loop.run(conn, 'cmd:Test', 'workers', onMessage);
178
+ yield runPromise;
179
+ // Nie powinien logować błędu (running = false = graceful shutdown)
180
+ expect(logger.error).not.toHaveBeenCalled();
181
+ }));
182
+ it('powinien limitować concurrency do skonfigurowanego limitu', () => __awaiter(void 0, void 0, void 0, function* () {
183
+ const smallLoop = new consumer_loop_1.ConsumerLoop({
184
+ consumerId: 'test-consumer',
185
+ batchSize: 10,
186
+ concurrency: 2,
187
+ logger,
188
+ });
189
+ const conn = createMockConnection();
190
+ const handlerResolves = [];
191
+ const onMessage = jest.fn().mockImplementation(() => new Promise((resolve) => {
192
+ handlerResolves.push(resolve);
193
+ }));
194
+ // Zwróć 5 wiadomości naraz
195
+ conn.xreadgroup.mockResolvedValueOnce([
196
+ [
197
+ 'cmd:Test',
198
+ [
199
+ ['msg-1', ['data', 'p1']],
200
+ ['msg-2', ['data', 'p2']],
201
+ ],
202
+ ],
203
+ ]);
204
+ const runPromise = smallLoop.run(conn, 'cmd:Test', 'workers', onMessage);
205
+ yield new Promise((r) => setTimeout(r, 20));
206
+ // Callback powinien być wywołany 2 razy (concurrency = 2)
207
+ expect(onMessage).toHaveBeenCalledTimes(2);
208
+ // Cleanup
209
+ handlerResolves.forEach((r) => r());
210
+ smallLoop.running = false;
211
+ conn.disconnect();
212
+ yield runPromise;
213
+ }));
214
+ });
215
+ });
216
+ //# sourceMappingURL=consumer-loop.spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"consumer-loop.spec.js","sourceRoot":"","sources":["../../../src/command-bus/transport/consumer-loop.spec.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Moduł transportu dla CommandBus
3
+ *
4
+ * Eksportuje interfejsy segregowane (ISP) i fasadę RedisStreamsTransport
5
+ * oraz poszczególne komponenty dla zaawansowanego użycia
6
+ */
7
+ export type { ITransport, IStreamProducer, IStreamConsumer, IRpcTransport, IClosable, ConsumerHandler, RpcMessageMetadata, } from './transport.interface';
8
+ export { default as RedisStreamsTransport } from './redis-streams-transport';
9
+ export type { RedisStreamsTransportOptions } from './redis-streams-transport';
10
+ export { RedisCodec } from './redis-codec';
11
+ export { StreamProducer } from './stream-producer';
12
+ export { StreamConsumer } from './stream-consumer';
13
+ export type { StreamConsumerOptions } from './stream-consumer';
14
+ export { MessageProcessor } from './message-processor';
15
+ export type { MessageProcessorOptions, RpcResponder } from './message-processor';
16
+ export { ConsumerLoop } from './consumer-loop';
17
+ export type { ConsumerLoopOptions, MessageCallback } from './consumer-loop';
18
+ export { RpcHandler } from './rpc-handler';
19
+ export type { RpcEnvelope } from './rpc-handler';
20
+ export { PendingRecovery } from './pending-recovery';
21
+ export type { PendingRecoveryOptions } from './pending-recovery';
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.PendingRecovery = exports.RpcHandler = exports.ConsumerLoop = exports.MessageProcessor = exports.StreamConsumer = exports.StreamProducer = exports.RedisCodec = exports.RedisStreamsTransport = void 0;
7
+ var redis_streams_transport_1 = require("./redis-streams-transport");
8
+ Object.defineProperty(exports, "RedisStreamsTransport", { enumerable: true, get: function () { return __importDefault(redis_streams_transport_1).default; } });
9
+ var redis_codec_1 = require("./redis-codec");
10
+ Object.defineProperty(exports, "RedisCodec", { enumerable: true, get: function () { return redis_codec_1.RedisCodec; } });
11
+ var stream_producer_1 = require("./stream-producer");
12
+ Object.defineProperty(exports, "StreamProducer", { enumerable: true, get: function () { return stream_producer_1.StreamProducer; } });
13
+ var stream_consumer_1 = require("./stream-consumer");
14
+ Object.defineProperty(exports, "StreamConsumer", { enumerable: true, get: function () { return stream_consumer_1.StreamConsumer; } });
15
+ var message_processor_1 = require("./message-processor");
16
+ Object.defineProperty(exports, "MessageProcessor", { enumerable: true, get: function () { return message_processor_1.MessageProcessor; } });
17
+ var consumer_loop_1 = require("./consumer-loop");
18
+ Object.defineProperty(exports, "ConsumerLoop", { enumerable: true, get: function () { return consumer_loop_1.ConsumerLoop; } });
19
+ var rpc_handler_1 = require("./rpc-handler");
20
+ Object.defineProperty(exports, "RpcHandler", { enumerable: true, get: function () { return rpc_handler_1.RpcHandler; } });
21
+ var pending_recovery_1 = require("./pending-recovery");
22
+ Object.defineProperty(exports, "PendingRecovery", { enumerable: true, get: function () { return pending_recovery_1.PendingRecovery; } });
23
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/command-bus/transport/index.ts"],"names":[],"mappings":";;;;;;AAeA,qEAA6E;AAApE,iJAAA,OAAO,OAAyB;AAEzC,6CAA2C;AAAlC,yGAAA,UAAU,OAAA;AACnB,qDAAmD;AAA1C,iHAAA,cAAc,OAAA;AACvB,qDAAmD;AAA1C,iHAAA,cAAc,OAAA;AAEvB,yDAAuD;AAA9C,qHAAA,gBAAgB,OAAA;AAEzB,iDAA+C;AAAtC,6GAAA,YAAY,OAAA;AAErB,6CAA2C;AAAlC,yGAAA,UAAU,OAAA;AAEnB,uDAAqD;AAA5C,mHAAA,eAAe,OAAA"}
@@ -0,0 +1,59 @@
1
+ import type { ILogger } from '../../shared/types';
2
+ import type { ISerializer } from '../serialization/serializer.interface';
3
+ import type { ConsumerHandler } from './transport.interface';
4
+ import type RedisConnectionPool from '../../shared/redis/connection-pool';
5
+ /**
6
+ * Typ callbacka do wysyłania odpowiedzi RPC
7
+ */
8
+ export type RpcResponder = (responseKey: string, data: Buffer, ttl: number) => Promise<void>;
9
+ /**
10
+ * Konfiguracja MessageProcessor
11
+ */
12
+ export interface MessageProcessorOptions {
13
+ pool: RedisConnectionPool;
14
+ serializer: ISerializer;
15
+ logger: ILogger;
16
+ batchSize: number;
17
+ maxRetained: number;
18
+ rpcRespond: RpcResponder;
19
+ }
20
+ /**
21
+ * Procesor wiadomości — parsuje, waliduje, przetwarza i potwierdza wiadomości
22
+ *
23
+ * Odpowiedzialności:
24
+ * - Parsowanie fields → fieldMap
25
+ * - Walidacja danych wejściowych (H4)
26
+ * - Detekcja RPC via marker field
27
+ * - Wywołanie handlera
28
+ * - XACK + throttled XTRIM (H2: per-stream counters)
29
+ * - Wysyłanie odpowiedzi RPC
30
+ *
31
+ * NIE odpowiada za deduplicację — to odpowiedzialność koordynatora (StreamConsumer)
32
+ */
33
+ export declare class MessageProcessor {
34
+ private readonly pool;
35
+ private readonly serializer;
36
+ private readonly logger;
37
+ private readonly batchSize;
38
+ private readonly maxRetained;
39
+ private readonly rpcRespond;
40
+ /** H2: Liczniki wiadomości od ostatniego XTRIM — per strumień */
41
+ private readonly xtrimCounters;
42
+ constructor(options: MessageProcessorOptions);
43
+ /**
44
+ * Czyści stan counters — wywoływane przy close()
45
+ */
46
+ reset(): void;
47
+ /**
48
+ * Przetwarza wiadomość — parsuje fields, wykrywa RPC, wywołuje handler, XACK/XTRIM
49
+ *
50
+ * Błędy propagują do callera (koordynatora) — nie łapie wewnętrznie
51
+ *
52
+ * @param streamName - Nazwa strumienia Redis
53
+ * @param groupName - Nazwa grupy konsumentów
54
+ * @param messageId - ID wiadomości
55
+ * @param fields - Tablica pól ze strumienia [key, value, key, value, ...]
56
+ * @param handler - Handler przetwarzający dane komendy
57
+ */
58
+ process(streamName: string, groupName: string, messageId: string, fields: string[], handler: ConsumerHandler): Promise<void>;
59
+ }
@@ -0,0 +1,111 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.MessageProcessor = void 0;
13
+ const redis_codec_1 = require("./redis-codec");
14
+ /**
15
+ * Procesor wiadomości — parsuje, waliduje, przetwarza i potwierdza wiadomości
16
+ *
17
+ * Odpowiedzialności:
18
+ * - Parsowanie fields → fieldMap
19
+ * - Walidacja danych wejściowych (H4)
20
+ * - Detekcja RPC via marker field
21
+ * - Wywołanie handlera
22
+ * - XACK + throttled XTRIM (H2: per-stream counters)
23
+ * - Wysyłanie odpowiedzi RPC
24
+ *
25
+ * NIE odpowiada za deduplicację — to odpowiedzialność koordynatora (StreamConsumer)
26
+ */
27
+ class MessageProcessor {
28
+ constructor(options) {
29
+ /** H2: Liczniki wiadomości od ostatniego XTRIM — per strumień */
30
+ this.xtrimCounters = new Map();
31
+ this.pool = options.pool;
32
+ this.serializer = options.serializer;
33
+ this.logger = options.logger;
34
+ this.batchSize = options.batchSize;
35
+ this.maxRetained = options.maxRetained;
36
+ this.rpcRespond = options.rpcRespond;
37
+ }
38
+ /**
39
+ * Czyści stan counters — wywoływane przy close()
40
+ */
41
+ reset() {
42
+ this.xtrimCounters.clear();
43
+ }
44
+ /**
45
+ * Przetwarza wiadomość — parsuje fields, wykrywa RPC, wywołuje handler, XACK/XTRIM
46
+ *
47
+ * Błędy propagują do callera (koordynatora) — nie łapie wewnętrznie
48
+ *
49
+ * @param streamName - Nazwa strumienia Redis
50
+ * @param groupName - Nazwa grupy konsumentów
51
+ * @param messageId - ID wiadomości
52
+ * @param fields - Tablica pól ze strumienia [key, value, key, value, ...]
53
+ * @param handler - Handler przetwarzający dane komendy
54
+ */
55
+ process(streamName, groupName, messageId, fields, handler) {
56
+ return __awaiter(this, void 0, void 0, function* () {
57
+ var _a;
58
+ // H4: Walidacja fields array — zapobiega crash na pustych/nieparzystych danych
59
+ if (!fields || fields.length < 2) {
60
+ this.logger.warn('Nieprawidłowa wiadomość — brak danych', { streamName, messageId });
61
+ yield this.pool.next().xack(streamName, groupName, messageId);
62
+ return;
63
+ }
64
+ const fieldMap = new Map();
65
+ for (let i = 0; i < fields.length; i += 2) {
66
+ if (i + 1 < fields.length) {
67
+ fieldMap.set(fields[i], fields[i + 1]);
68
+ }
69
+ }
70
+ const rawData = fieldMap.get('data');
71
+ // H4: Walidacja rawData przed decode
72
+ if (rawData === undefined || rawData === null) {
73
+ this.logger.warn('Wiadomość bez pola data', { streamName, messageId });
74
+ yield this.pool.next().xack(streamName, groupName, messageId);
75
+ return;
76
+ }
77
+ const dataBuffer = redis_codec_1.RedisCodec.decode(rawData);
78
+ let commandData;
79
+ let rpcMetadata;
80
+ if (fieldMap.has('rpc')) {
81
+ const envelope = this.serializer.deserialize(dataBuffer);
82
+ commandData = redis_codec_1.RedisCodec.decode(envelope.commandData);
83
+ rpcMetadata = envelope.rpc;
84
+ }
85
+ else {
86
+ commandData = dataBuffer;
87
+ }
88
+ const result = yield handler(commandData);
89
+ // H2: XACK + throttled XTRIM per strumień
90
+ const count = ((_a = this.xtrimCounters.get(streamName)) !== null && _a !== void 0 ? _a : 0) + 1;
91
+ this.xtrimCounters.set(streamName, count);
92
+ const conn = this.pool.next();
93
+ if (count >= this.batchSize) {
94
+ const pipeline = conn.pipeline();
95
+ pipeline.xack(streamName, groupName, messageId);
96
+ pipeline.xtrim(streamName, 'MAXLEN', '~', this.maxRetained);
97
+ yield pipeline.exec();
98
+ this.xtrimCounters.set(streamName, 0);
99
+ }
100
+ else {
101
+ yield conn.xack(streamName, groupName, messageId);
102
+ }
103
+ if (rpcMetadata) {
104
+ const responseBuffer = this.serializer.serialize({ result, error: null });
105
+ yield this.rpcRespond(rpcMetadata.responseKey, responseBuffer, 60);
106
+ }
107
+ });
108
+ }
109
+ }
110
+ exports.MessageProcessor = MessageProcessor;
111
+ //# sourceMappingURL=message-processor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"message-processor.js","sourceRoot":"","sources":["../../../src/command-bus/transport/message-processor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,185 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ const message_processor_1 = require("./message-processor");
13
+ const redis_codec_1 = require("./redis-codec");
14
+ /**
15
+ * Mock helpers
16
+ */
17
+ function createMockLogger() {
18
+ return {
19
+ log: jest.fn(),
20
+ error: jest.fn(),
21
+ warn: jest.fn(),
22
+ debug: jest.fn(),
23
+ };
24
+ }
25
+ function createMockSerializer() {
26
+ return {
27
+ serialize: jest.fn((data) => Buffer.from(JSON.stringify(data))),
28
+ deserialize: jest.fn((buf) => JSON.parse(buf.toString())),
29
+ };
30
+ }
31
+ function createMockConnection() {
32
+ return {
33
+ xack: jest.fn().mockResolvedValue(1),
34
+ pipeline: jest.fn().mockReturnValue({
35
+ xack: jest.fn().mockReturnThis(),
36
+ xtrim: jest.fn().mockReturnThis(),
37
+ exec: jest.fn().mockResolvedValue([
38
+ [null, 1],
39
+ [null, 0],
40
+ ]),
41
+ }),
42
+ };
43
+ }
44
+ function createMockPool() {
45
+ const conn = createMockConnection();
46
+ return {
47
+ pool: { next: jest.fn().mockReturnValue(conn) },
48
+ conn,
49
+ };
50
+ }
51
+ describe('MessageProcessor', () => {
52
+ let processor;
53
+ let logger;
54
+ let serializer;
55
+ let mockConn;
56
+ let mockPool;
57
+ const rpcRespond = jest.fn().mockResolvedValue(undefined);
58
+ beforeEach(() => {
59
+ jest.clearAllMocks();
60
+ logger = createMockLogger();
61
+ serializer = createMockSerializer();
62
+ const poolMock = createMockPool();
63
+ mockPool = poolMock.pool;
64
+ mockConn = poolMock.conn;
65
+ processor = new message_processor_1.MessageProcessor({
66
+ pool: mockPool,
67
+ serializer,
68
+ logger,
69
+ batchSize: 10,
70
+ maxRetained: 10000,
71
+ rpcRespond,
72
+ });
73
+ });
74
+ describe('process()', () => {
75
+ it('powinien przetworzyć wiadomość i wywołać handler', () => __awaiter(void 0, void 0, void 0, function* () {
76
+ const handler = jest.fn().mockResolvedValue('ok');
77
+ const testPayload = redis_codec_1.RedisCodec.encode(Buffer.from('test-data'));
78
+ const fields = ['data', testPayload];
79
+ yield processor.process('cmd:Test', 'workers', 'msg-1', fields, handler);
80
+ expect(handler).toHaveBeenCalledTimes(1);
81
+ expect(handler).toHaveBeenCalledWith(expect.any(Buffer));
82
+ }));
83
+ it('powinien XACK wiadomość po przetworzeniu', () => __awaiter(void 0, void 0, void 0, function* () {
84
+ const handler = jest.fn().mockResolvedValue('ok');
85
+ const fields = ['data', redis_codec_1.RedisCodec.encode(Buffer.from('data'))];
86
+ yield processor.process('cmd:Test', 'workers', 'msg-1', fields, handler);
87
+ expect(mockConn.xack).toHaveBeenCalledWith('cmd:Test', 'workers', 'msg-1');
88
+ }));
89
+ it('powinien odrzucić wiadomość z pustym fields array (H4)', () => __awaiter(void 0, void 0, void 0, function* () {
90
+ const handler = jest.fn();
91
+ yield processor.process('cmd:Test', 'workers', 'msg-empty', [], handler);
92
+ expect(handler).not.toHaveBeenCalled();
93
+ expect(logger.warn).toHaveBeenCalledWith('Nieprawidłowa wiadomość — brak danych', expect.objectContaining({ messageId: 'msg-empty' }));
94
+ expect(mockConn.xack).toHaveBeenCalledWith('cmd:Test', 'workers', 'msg-empty');
95
+ }));
96
+ it('powinien odrzucić wiadomość z jednym elementem (H4)', () => __awaiter(void 0, void 0, void 0, function* () {
97
+ const handler = jest.fn();
98
+ yield processor.process('cmd:Test', 'workers', 'msg-odd', ['key-only'], handler);
99
+ expect(handler).not.toHaveBeenCalled();
100
+ expect(logger.warn).toHaveBeenCalledWith('Nieprawidłowa wiadomość — brak danych', expect.objectContaining({ messageId: 'msg-odd' }));
101
+ }));
102
+ it('powinien odrzucić wiadomość bez pola data (H4)', () => __awaiter(void 0, void 0, void 0, function* () {
103
+ const handler = jest.fn();
104
+ yield processor.process('cmd:Test', 'workers', 'msg-nodata', ['other', 'value'], handler);
105
+ expect(handler).not.toHaveBeenCalled();
106
+ expect(logger.warn).toHaveBeenCalledWith('Wiadomość bez pola data', expect.objectContaining({ messageId: 'msg-nodata' }));
107
+ }));
108
+ it('powinien obsłużyć nieparzystą liczbę elementów (H4)', () => __awaiter(void 0, void 0, void 0, function* () {
109
+ const handler = jest.fn().mockResolvedValue('ok');
110
+ const fields = ['data', redis_codec_1.RedisCodec.encode(Buffer.from('data')), 'extra-key'];
111
+ yield processor.process('cmd:Test', 'workers', 'msg-odd-fields', fields, handler);
112
+ expect(handler).toHaveBeenCalledTimes(1);
113
+ }));
114
+ it('powinien propagować błąd handlera do callera', () => __awaiter(void 0, void 0, void 0, function* () {
115
+ const handler = jest.fn().mockRejectedValue(new Error('Handler error'));
116
+ const fields = ['data', redis_codec_1.RedisCodec.encode(Buffer.from('data'))];
117
+ yield expect(processor.process('cmd:Test', 'workers', 'msg-err', fields, handler)).rejects.toThrow('Handler error');
118
+ }));
119
+ });
120
+ describe('RPC detection', () => {
121
+ it('powinien wykryć RPC wiadomość przez marker i odpowiedzieć', () => __awaiter(void 0, void 0, void 0, function* () {
122
+ const handler = jest.fn().mockResolvedValue('result-42');
123
+ const envelope = {
124
+ commandData: redis_codec_1.RedisCodec.encode(Buffer.from('cmd-data')),
125
+ rpc: { correlationId: 'corr-1', responseKey: 'rpc:res:corr-1' },
126
+ };
127
+ const envelopePayload = redis_codec_1.RedisCodec.encode(Buffer.from(JSON.stringify(envelope)));
128
+ const fields = ['data', envelopePayload, 'rpc', '1'];
129
+ yield processor.process('cmd:Test', 'workers', 'msg-rpc', fields, handler);
130
+ expect(handler).toHaveBeenCalledTimes(1);
131
+ expect(rpcRespond).toHaveBeenCalledWith('rpc:res:corr-1', expect.any(Buffer), 60);
132
+ }));
133
+ it('powinien nie wywoływać rpcRespond dla zwykłej wiadomości', () => __awaiter(void 0, void 0, void 0, function* () {
134
+ const handler = jest.fn().mockResolvedValue('ok');
135
+ const fields = ['data', redis_codec_1.RedisCodec.encode(Buffer.from('normal-data'))];
136
+ yield processor.process('cmd:Test', 'workers', 'msg-normal', fields, handler);
137
+ expect(handler).toHaveBeenCalledTimes(1);
138
+ expect(rpcRespond).not.toHaveBeenCalled();
139
+ }));
140
+ });
141
+ describe('XTRIM per-stream (H2)', () => {
142
+ it('powinien zliczać XTRIM niezależnie per strumień', () => __awaiter(void 0, void 0, void 0, function* () {
143
+ const handler = jest.fn().mockResolvedValue('ok');
144
+ const fields = ['data', redis_codec_1.RedisCodec.encode(Buffer.from('data'))];
145
+ // 9 wiadomości na stream A — nie powinno triggerować XTRIM (batchSize=10)
146
+ for (let i = 0; i < 9; i++) {
147
+ yield processor.process('cmd:StreamA', 'workers', `a-${i}`, fields, handler);
148
+ }
149
+ // 1 wiadomość na stream B
150
+ yield processor.process('cmd:StreamB', 'workers', 'b-0', fields, handler);
151
+ // Pipeline NIE powinien być wywołany — żaden stream nie osiągnął batchSize
152
+ const xackCalls = mockConn.xack.mock.calls;
153
+ expect(xackCalls.length).toBe(10);
154
+ // 10. wiadomość na stream A — powinno triggerować XTRIM
155
+ yield processor.process('cmd:StreamA', 'workers', 'a-9', fields, handler);
156
+ expect(mockConn.pipeline).toHaveBeenCalled();
157
+ }));
158
+ it('powinien wykonać pipeline XACK+XTRIM co batchSize', () => __awaiter(void 0, void 0, void 0, function* () {
159
+ const handler = jest.fn().mockResolvedValue('ok');
160
+ const fields = ['data', redis_codec_1.RedisCodec.encode(Buffer.from('data'))];
161
+ for (let i = 0; i < 10; i++) {
162
+ yield processor.process('cmd:Test', 'workers', `msg-${i}`, fields, handler);
163
+ }
164
+ expect(mockConn.pipeline).toHaveBeenCalledTimes(1);
165
+ }));
166
+ it('powinien zresetować counter po XTRIM', () => __awaiter(void 0, void 0, void 0, function* () {
167
+ const handler = jest.fn().mockResolvedValue('ok');
168
+ const fields = ['data', redis_codec_1.RedisCodec.encode(Buffer.from('data'))];
169
+ // Pierwsze 10 — trigger XTRIM
170
+ for (let i = 0; i < 10; i++) {
171
+ yield processor.process('cmd:Test', 'workers', `batch1-${i}`, fields, handler);
172
+ }
173
+ expect(mockConn.pipeline).toHaveBeenCalledTimes(1);
174
+ // Następne 9 — NIE trigger
175
+ for (let i = 0; i < 9; i++) {
176
+ yield processor.process('cmd:Test', 'workers', `batch2-${i}`, fields, handler);
177
+ }
178
+ expect(mockConn.pipeline).toHaveBeenCalledTimes(1);
179
+ // 20. wiadomość — trigger XTRIM ponownie
180
+ yield processor.process('cmd:Test', 'workers', 'batch2-9', fields, handler);
181
+ expect(mockConn.pipeline).toHaveBeenCalledTimes(2);
182
+ }));
183
+ });
184
+ });
185
+ //# sourceMappingURL=message-processor.spec.js.map