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