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
@@ -8,73 +8,101 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
8
8
  step((generator = generator.apply(thisArg, _arguments || [])).next());
9
9
  });
10
10
  };
11
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
11
14
  Object.defineProperty(exports, "__esModule", { value: true });
12
- const queue_1 = require("./queue");
13
- const worker_1 = require("./worker");
14
- const job_1 = require("./job");
15
- const rpc_1 = require("./rpc");
15
+ const serialization_1 = require("./serialization");
16
+ const transport_1 = require("./transport");
17
+ const connection_pool_1 = __importDefault(require("../shared/redis/connection-pool"));
18
+ const rpc_connection_pool_1 = __importDefault(require("../shared/redis/rpc-connection-pool"));
16
19
  const logging_1 = require("./logging");
17
- const redis_1 = require("../shared/redis");
20
+ const interceptors_1 = require("./interceptors");
21
+ const error_utils_1 = require("../shared/utils/error-utils");
18
22
  /**
19
- * Command Bus wykorzystujący BullMQ
23
+ * Command Bus oparty na Redis Streams + DragonflyDB
24
+ *
20
25
  * Obsługuje komendy w relacji 1:1 (jedna komenda = jeden handler)
26
+ * API: dispatch(), dispatchBatch(), call(), handle(), close()
27
+ *
28
+ * Technologie:
29
+ * - Redis Streams (XADD/XREADGROUP) — natywny transport
30
+ * - MessagePack — binarna serializacja z obsługą Date
31
+ * - LPUSH/BRPOP — point-to-point RPC
32
+ * - Connection pool z round-robin — wielowątkowy DragonflyDB
21
33
  */
22
34
  class CommandBus {
23
35
  constructor(config) {
24
36
  this.config = config;
25
37
  /**
26
- * Handlery komend - tylko jeden per typ komendy
38
+ * Handlery komend tylko jeden per typ komendy
27
39
  */
28
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
29
40
  this.commandHandlers = {};
30
- // Używaj loggera z konfiguracji (już zawiera filtrowanie według logLevel)
41
+ /**
42
+ * Promises z transport.consume() — do graceful shutdown
43
+ */
44
+ this.consumePromises = [];
31
45
  this.logger = config.logger;
32
46
  this.logger.debug('Konstruktor CommandBus', {
33
- config: this.config,
47
+ config: {
48
+ poolSize: config.poolSize,
49
+ maxConcurrentRpc: config.maxConcurrentRpc,
50
+ batchSize: config.batchSize,
51
+ maxAttempts: config.maxAttempts,
52
+ claimTimeout: config.claimTimeout,
53
+ maxRetained: config.maxRetained,
54
+ },
34
55
  timestamp: new Date().toISOString(),
35
56
  });
36
- // Fabryka połączeń Redis z obsługą błędów i eventów
37
- const redisFactory = new redis_1.RedisConnectionFactory(this.logger);
38
- // Utwórz Redis connections przez fabrykę
39
- // getRedisOptions() zwraca ConnectionOptions z BullMQ, które są kompatybilne z RedisConnectionOptions
57
+ // Serializer: MessagePack z natywną obsługą Date (eliminuje reconstructDates)
58
+ this.serializer = new serialization_1.MsgpackSerializer();
59
+ // Opcje Redis z konfiguracji
40
60
  const redisOptions = this.config.getRedisOptions();
41
- // QueueManager - standardowe opcje Redis
42
- this.queueRedisConnection = redisFactory.create(redisOptions, 'QueueManager');
43
- // WorkerOrchestrator - opcje z maxRetriesPerRequest: null dla Worker compatibility
44
- this.workerRedisConnection = redisFactory.createForWorker(redisOptions, 'WorkerOrchestrator');
45
- // RpcCoordinator - opcje z maxRetriesPerRequest: null dla Worker compatibility
46
- this.rpcRedisConnection = redisFactory.createForWorker(redisOptions, 'RpcCoordinator');
47
- // Utwórz QueueManager z własnym Redis connection
48
- this.queueManager = new queue_1.QueueManager(this.queueRedisConnection, this.logger);
49
- // Utwórz PayloadCompressionService z threshold z konfiguracji (współdzielony serwis)
50
- this.compressionService = new rpc_1.PayloadCompressionService(this.config.compressionThreshold, this.logger);
51
- // Utwórz RpcJobCancellationService do zarządzania anulowaniem jobów RPC
52
- this.cancellationService = new rpc_1.RpcJobCancellationService(this.rpcRedisConnection, this.logger);
53
- // Utwórz RpcCoordinator z PayloadCompressionService i CancellationService (używa Pub/Sub)
54
- this.rpcCoordinator = new rpc_1.RpcCoordinator(this.logger, this.rpcRedisConnection, this.compressionService, this.cancellationService, this.createRemoveJobCallback());
55
- // Utwórz JobOptionsBuilder
56
- this.jobOptionsBuilder = new job_1.JobOptionsBuilder(this.config);
57
- // Utwórz CommandLogger jeśli commandLog jest skonfigurowane
61
+ // Pula połączeń Redis — round-robin dla XADD, XACK, DEL, pipeline
62
+ this.connectionPool = new connection_pool_1.default({
63
+ size: config.poolSize,
64
+ redisOptions,
65
+ logger: this.logger,
66
+ });
67
+ // Pula połączeń RPC bounded, lazy, dla blocking BRPOP
68
+ this.rpcConnectionPool = new rpc_connection_pool_1.default({
69
+ maxSize: config.maxConcurrentRpc,
70
+ redisOptions,
71
+ logger: this.logger,
72
+ });
73
+ // Interceptor wydajności z konfiguracją
74
+ this.performanceInterceptor = new interceptors_1.PerformanceInterceptor(this.logger, config.slowHandlerThreshold);
75
+ // Transport: Redis Streams
76
+ this.transport = new transport_1.RedisStreamsTransport({
77
+ pool: this.connectionPool,
78
+ rpcPool: this.rpcConnectionPool,
79
+ serializer: this.serializer,
80
+ logger: this.logger,
81
+ maxRetained: config.maxRetained,
82
+ maxAttempts: config.maxAttempts,
83
+ claimTimeout: config.claimTimeout,
84
+ batchSize: config.batchSize,
85
+ concurrency: config.concurrency,
86
+ interceptor: this.performanceInterceptor,
87
+ });
88
+ // CommandLogger jeśli commandLog jest skonfigurowane
58
89
  if (this.config.commandLog) {
59
90
  this.commandLogger = new logging_1.CommandLogger(this.config.commandLog, this.logger);
60
91
  }
61
- // Utwórz JobProcessor z Redis connection dla Pub/Sub, compressionService i cancellationService
62
- this.jobProcessor = new job_1.JobProcessor(this.commandHandlers, this.rpcRedisConnection, this.logger, this.jobOptionsBuilder, this.compressionService, this.commandLogger, this.cancellationService);
63
- // Utwórz WorkerOrchestrator z własnym Redis connection
64
- this.workerOrchestrator = new worker_1.WorkerOrchestrator(this.workerRedisConnection, this.jobProcessor, this.config.concurrency, this.config.maxAttempts, this.logger);
65
- this.logger.debug('CommandBus gotowy do użycia', {
92
+ this.logger.log('CommandBus gotowy do użycia', {
93
+ poolSize: this.config.poolSize,
94
+ maxConcurrentRpc: this.config.maxConcurrentRpc,
66
95
  timestamp: new Date().toISOString(),
67
96
  });
68
97
  }
69
98
  /**
70
- * Wysyła komendę do kolejki
71
- * Automatycznie kompresuje dane jeśli przekraczają threshold
72
- * Używa cache kolejek dla optymalizacji pamięci
99
+ * Wysyła komendę do strumienia (fire-and-forget)
100
+ * XADD = 1 natywne polecenie Redis
101
+ *
73
102
  * @param command - Komenda do wysłania
74
103
  */
75
104
  dispatch(command) {
76
105
  return __awaiter(this, void 0, void 0, function* () {
77
- var _a;
78
106
  const commandName = command.__name;
79
107
  const commandId = command.__id;
80
108
  const timestamp = new Date().toISOString();
@@ -83,141 +111,129 @@ class CommandBus {
83
111
  commandId,
84
112
  timestamp,
85
113
  });
86
- // Skompresuj komendę jeśli przekracza threshold (używa współdzielonego serwisu)
87
- const processedCommand = yield this.compressionService.compressCommand(command);
88
- const queue = this.queueManager.getOrCreateQueue(commandName);
89
- const job = yield queue.add(commandName, processedCommand, this.jobOptionsBuilder.buildStandardOptions());
90
- this.logger.debug('Komenda dodana do kolejki', {
114
+ const data = this.serializer.serialize(command);
115
+ const messageId = yield this.transport.enqueue(`cmd:${commandName}`, data);
116
+ this.logger.debug('Komenda dodana do strumienia', {
91
117
  commandName,
92
118
  commandId,
93
- jobId: job.id,
94
- compressed: processedCommand.__compressed,
95
- queuePosition: ((_a = job.opts) === null || _a === void 0 ? void 0 : _a.delay) ? 'delayed' : 'active',
119
+ messageId,
96
120
  timestamp,
97
121
  });
98
122
  });
99
123
  }
124
+ /**
125
+ * Wysyła wiele komend naraz z użyciem pipelining
126
+ * DragonflyDB przetwarza pipeline równolegle na wielu wątkach
127
+ *
128
+ * @param commands - Tablica komend do wysłania
129
+ */
130
+ dispatchBatch(commands) {
131
+ return __awaiter(this, void 0, void 0, function* () {
132
+ if (commands.length === 0)
133
+ return;
134
+ this.logger.debug('Wysyłanie batch komend', {
135
+ count: commands.length,
136
+ timestamp: new Date().toISOString(),
137
+ });
138
+ const entries = commands.map((cmd) => ({
139
+ streamName: `cmd:${cmd.__name}`,
140
+ data: this.serializer.serialize(cmd),
141
+ }));
142
+ yield this.transport.enqueueBatch(entries);
143
+ this.logger.debug('Batch komend wysłany', {
144
+ count: commands.length,
145
+ timestamp: new Date().toISOString(),
146
+ });
147
+ });
148
+ }
100
149
  /**
101
150
  * Rejestruje handler dla komendy
102
- * Uruchamia benchmark aby ustalić optymalne concurrency
151
+ *
103
152
  * @param commandDefinition - Definicja komendy (klasa)
104
153
  * @param handler - Handler do obsługi komendy
105
154
  */
106
- handle(
107
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
108
- commandDefinition, handler) {
155
+ handle(commandDefinition, handler) {
109
156
  const commandName = commandDefinition.name;
110
157
  if (this.commandHandlers[commandName]) {
111
158
  throw new Error(`Handler dla komendy ${commandName} już istnieje`);
112
159
  }
113
160
  this.commandHandlers[commandName] = handler;
114
- this.workerOrchestrator.registerWorker(commandName);
161
+ // Zarejestruj konsumenta strumienia — śledź promise do graceful shutdown
162
+ const consumePromise = this.transport
163
+ .consume(`cmd:${commandName}`, 'workers', (data) => __awaiter(this, void 0, void 0, function* () {
164
+ const command = this.serializer.deserialize(data);
165
+ // Opcjonalne logowanie komendy
166
+ if (this.commandLogger) {
167
+ void this.commandLogger.logCommand(command);
168
+ }
169
+ return yield handler(command);
170
+ }))
171
+ .catch((error) => {
172
+ this.logger.error('Błąd konsumenta strumienia', {
173
+ commandName,
174
+ error: (0, error_utils_1.getErrorMessage)(error),
175
+ timestamp: new Date().toISOString(),
176
+ });
177
+ });
178
+ this.consumePromises.push(consumePromise);
115
179
  this.logger.debug(`Zarejestrowano handler dla komendy ${commandName}`);
116
180
  }
117
181
  /**
118
182
  * Synchroniczne wywołanie komendy z oczekiwaniem na wynik (RPC)
119
- * Request przez BullMQ, odpowiedź przez Redis Pub/Sub
120
- * Automatycznie kompresuje dane jeśli przekraczają threshold
183
+ * Request przez Redis Streams, odpowiedź przez LPUSH/BRPOP
121
184
  *
122
- * Flow RPC:
123
- * 1. Rejestruj pending call (dostaje responsePromise)
124
- * 2. Skompresuj komendę jeśli przekracza threshold
125
- * 3. Dodaj job do kolejki BullMQ
126
- * 4. Zwróć responsePromise (worker wyśle odpowiedź przez Pub/Sub)
185
+ * Flow (4 komendy Redis):
186
+ * 1. XADD komenda z metadanymi RPC do strumienia
187
+ * 2. BRPOP czekaj na odpowiedź na dedykowanym połączeniu
188
+ * 3. Worker: LPUSH odpowiedź na klucz
189
+ * 4. DEL cleanup klucza (TTL safety net)
127
190
  *
128
191
  * @param command - Komenda do wykonania
129
192
  * @param timeout - Timeout w milisekundach (domyślnie 30s)
130
193
  */
131
194
  call(command_1) {
132
195
  return __awaiter(this, arguments, void 0, function* (command, timeout = 30000) {
133
- var _a, _b;
134
196
  const commandName = command.__name;
135
197
  const correlationId = command.__id;
136
198
  const timestamp = new Date().toISOString();
137
- this.logger.debug('Rozpoczynam wywołanie RPC przez Pub/Sub', {
199
+ this.logger.debug('Rozpoczynam wywołanie RPC', {
138
200
  commandName,
139
201
  commandId: correlationId,
140
202
  timeout: `${timeout}ms`,
141
203
  timestamp,
142
204
  });
143
- // Krok 1: Zarejestruj pending call (subskrybuje kanał Pub/Sub dla odpowiedzi)
144
- // registerCall() zwraca responsePromise natychmiast (nie blokuje)
145
- const promise = this.rpcCoordinator.registerCall(correlationId, commandName, timeout);
146
- // Krok 2: Skompresuj komendę jeśli przekracza threshold (używa współdzielonego serwisu)
147
- const compressedCommand = yield this.compressionService.compressCommand(command);
148
- // Krok 3: Wyślij komendę do kolejki z metadanymi RPC (używa cache)
149
- // RpcCoordinator sam zarządza responseChannel z processInstanceId
150
- const queue = this.queueManager.getOrCreateQueue(commandName);
151
- const commandWithMetadata = this.rpcCoordinator.prepareRpcCommand(compressedCommand);
152
- const job = yield queue.add(commandName, commandWithMetadata, this.jobOptionsBuilder.buildStandardOptions());
153
- this.logger.debug('Komenda RPC dodana do kolejki', {
205
+ const startTime = Date.now();
206
+ const data = this.serializer.serialize(command);
207
+ const resultBuffer = yield this.transport.rpcCall(commandName, data, timeout);
208
+ const duration = Date.now() - startTime;
209
+ // Deserializuj odpowiedź RPC
210
+ const response = this.serializer.deserialize(resultBuffer);
211
+ if (response.error) {
212
+ throw new Error(response.error);
213
+ }
214
+ this.logger.log('Wywołanie RPC zakończone', {
154
215
  commandName,
155
216
  commandId: correlationId,
156
- jobId: job.id,
157
- compressed: compressedCommand.__compressed,
158
- responseChannel: (_a = commandWithMetadata.__rpcMetadata) === null || _a === void 0 ? void 0 : _a.responseChannel,
159
- queuePosition: ((_b = job.opts) === null || _b === void 0 ? void 0 : _b.delay) ? 'delayed' : 'active',
160
- timestamp,
217
+ duration,
218
+ timestamp: new Date().toISOString(),
161
219
  });
162
- // Krok 4: Przekaż jobId do RpcCoordinator dla możliwości usunięcia przy timeout
163
- if (job.id) {
164
- this.rpcCoordinator.setJobId(correlationId, job.id, commandName);
165
- }
166
- // Krok 5: Zwróć responsePromise - zostanie resolved gdy worker wyśle odpowiedź przez Pub/Sub
167
- return promise;
168
- });
169
- }
170
- /**
171
- * Tworzy callback do usuwania jobów z kolejki
172
- * Callback jest przekazywany do RpcCoordinator dla możliwości usunięcia joba przy timeout
173
- * Nie rzuca wyjątków - zwraca boolean sukcesu
174
- */
175
- createRemoveJobCallback() {
176
- return (queueName, jobId) => __awaiter(this, void 0, void 0, function* () {
177
- try {
178
- const queue = this.queueManager.getOrCreateQueue(queueName);
179
- const job = yield queue.getJob(jobId);
180
- if (job) {
181
- yield job.remove();
182
- this.logger.debug('Job usunięty z kolejki (RPC timeout)', {
183
- queueName,
184
- jobId,
185
- timestamp: new Date().toISOString(),
186
- });
187
- return true;
188
- }
189
- return false;
190
- }
191
- catch (error) {
192
- this.logger.debug('Nie udało się usunąć joba z kolejki (prawdopodobnie już przetwarzany)', {
193
- queueName,
194
- jobId,
195
- error: error instanceof Error ? error.message : String(error),
196
- timestamp: new Date().toISOString(),
197
- });
198
- return false;
199
- }
220
+ return response.result;
200
221
  });
201
222
  }
202
223
  /**
203
224
  * Zamyka wszystkie połączenia
204
- * Czyści cache kolejek dla optymalizacji pamięci
205
225
  */
206
226
  close() {
207
227
  return __awaiter(this, void 0, void 0, function* () {
208
228
  this.logger.debug('Zamykanie połączeń CommandBus', {
209
229
  timestamp: new Date().toISOString(),
210
230
  });
211
- // Zamknij wszystkie workery
212
- yield this.workerOrchestrator.closeAll();
213
- // Zamknij wszystkie kolejki z cache
214
- yield this.queueManager.closeAllQueues();
215
- // Zamknij RpcCoordinator (async - zamyka shared subscriber)
216
- yield this.rpcCoordinator.close();
217
- // Zamknij pozostałe Redis connections
218
- yield this.queueRedisConnection.quit();
219
- yield this.workerRedisConnection.quit();
220
- yield this.rpcRedisConnection.quit();
231
+ // Czekaj na zakończenie rejestracji konsumentów
232
+ if (this.consumePromises.length > 0) {
233
+ yield Promise.allSettled(this.consumePromises);
234
+ this.consumePromises.length = 0;
235
+ }
236
+ yield this.transport.close();
221
237
  });
222
238
  }
223
239
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/command-bus/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/command-bus/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Export publiczny interceptorów
3
+ */
4
+ export * from './interceptor.interface';
5
+ export * from './performance-interceptor';
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ /**
18
+ * Export publiczny interceptorów
19
+ */
20
+ __exportStar(require("./interceptor.interface"), exports);
21
+ __exportStar(require("./performance-interceptor"), exports);
22
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/command-bus/interceptors/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA;;GAEG;AACH,0DAAwC;AACxC,4DAA0C"}
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Context przetwarzania komendy - przekazywany do interceptora
3
+ */
4
+ export interface CommandExecutionContext {
5
+ commandId: string;
6
+ commandName: string;
7
+ streamName: string;
8
+ messageId: string;
9
+ timestamp: number;
10
+ }
11
+ /**
12
+ * Wynik wykonania handlera - zwracany przez interceptor
13
+ */
14
+ export interface CommandExecutionResult<T = unknown> {
15
+ result: T;
16
+ duration: number;
17
+ success: boolean;
18
+ error?: Error;
19
+ }
20
+ /**
21
+ * Interface interceptora komend
22
+ *
23
+ * Interceptor umożliwia dodanie logiki przed/po wykonaniu handlera
24
+ * bez naruszania SRP MessageProcessor.
25
+ */
26
+ export interface ICommandInterceptor {
27
+ /**
28
+ * Wykonuje handler z logiką interceptora
29
+ *
30
+ * @param context - Kontekst wykonania komendy
31
+ * @param handler - Handler do wykonania
32
+ * @param commandData - Dane komendy
33
+ */
34
+ intercept<T>(context: CommandExecutionContext, handler: (data: Buffer) => Promise<T>, commandData: Buffer): Promise<CommandExecutionResult<T>>;
35
+ }
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=interceptor.interface.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"interceptor.interface.js","sourceRoot":"","sources":["../../../src/command-bus/interceptors/interceptor.interface.ts"],"names":[],"mappings":""}
@@ -0,0 +1,24 @@
1
+ import type { ILogger } from '../../shared/types';
2
+ import type { ICommandInterceptor, CommandExecutionContext, CommandExecutionResult } from './interceptor.interface';
3
+ /**
4
+ * Interceptor mierzący czas wykonania handlera
5
+ *
6
+ * Odpowiedzialności (SRP):
7
+ * - Pomiar czasu wykonania handlera
8
+ * - Logowanie metryk wydajności
9
+ * - Obsługa błędów z zachowaniem kontekstu
10
+ *
11
+ * NIE odpowiada za:
12
+ * - Przetwarzanie komendy (MessageProcessor)
13
+ * - XACK/XTRIM (MessageProcessor)
14
+ * - Deduplicję (StreamConsumer)
15
+ */
16
+ export declare class PerformanceInterceptor implements ICommandInterceptor {
17
+ private readonly logger;
18
+ private readonly slowThreshold;
19
+ constructor(logger: ILogger, slowThreshold?: number);
20
+ /**
21
+ * Wykonuje handler z pomiarem czasu
22
+ */
23
+ intercept<T>(context: CommandExecutionContext, handler: (data: Buffer) => Promise<T>, commandData: Buffer): Promise<CommandExecutionResult<T>>;
24
+ }
@@ -0,0 +1,86 @@
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.PerformanceInterceptor = void 0;
13
+ /**
14
+ * Interceptor mierzący czas wykonania handlera
15
+ *
16
+ * Odpowiedzialności (SRP):
17
+ * - Pomiar czasu wykonania handlera
18
+ * - Logowanie metryk wydajności
19
+ * - Obsługa błędów z zachowaniem kontekstu
20
+ *
21
+ * NIE odpowiada za:
22
+ * - Przetwarzanie komendy (MessageProcessor)
23
+ * - XACK/XTRIM (MessageProcessor)
24
+ * - Deduplicję (StreamConsumer)
25
+ */
26
+ class PerformanceInterceptor {
27
+ constructor(logger, slowThreshold = 1000) {
28
+ this.logger = logger;
29
+ this.slowThreshold = slowThreshold;
30
+ }
31
+ /**
32
+ * Wykonuje handler z pomiarem czasu
33
+ */
34
+ intercept(context, handler, commandData) {
35
+ return __awaiter(this, void 0, void 0, function* () {
36
+ const startTime = performance.now();
37
+ try {
38
+ const result = yield handler(commandData);
39
+ const duration = Math.round(performance.now() - startTime);
40
+ // KOMPROMIS: Log tylko jeśli przekroczono próg (unikanie log spam)
41
+ if (duration >= this.slowThreshold) {
42
+ this.logger.warn('Wolne wykonanie handlera', {
43
+ commandId: context.commandId,
44
+ commandName: context.commandName,
45
+ duration,
46
+ threshold: this.slowThreshold,
47
+ timestamp: new Date().toISOString(),
48
+ });
49
+ }
50
+ // Zawsze loguj na debug (dla profiling)
51
+ this.logger.debug('Handler wykonany', {
52
+ commandId: context.commandId,
53
+ commandName: context.commandName,
54
+ streamName: context.streamName,
55
+ messageId: context.messageId,
56
+ duration,
57
+ timestamp: new Date().toISOString(),
58
+ });
59
+ return {
60
+ result,
61
+ duration,
62
+ success: true,
63
+ };
64
+ }
65
+ catch (error) {
66
+ const duration = Math.round(performance.now() - startTime);
67
+ // Błędy loguj na debug (ERROR już jest w StreamConsumer)
68
+ this.logger.debug('Handler zakończony błędem', {
69
+ commandId: context.commandId,
70
+ commandName: context.commandName,
71
+ duration,
72
+ error: error instanceof Error ? error.message : String(error),
73
+ timestamp: new Date().toISOString(),
74
+ });
75
+ return {
76
+ result: undefined,
77
+ duration,
78
+ success: false,
79
+ error: error instanceof Error ? error : new Error(String(error)),
80
+ };
81
+ }
82
+ });
83
+ }
84
+ }
85
+ exports.PerformanceInterceptor = PerformanceInterceptor;
86
+ //# sourceMappingURL=performance-interceptor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"performance-interceptor.js","sourceRoot":"","sources":["../../../src/command-bus/interceptors/performance-interceptor.ts"],"names":[],"mappings":";;;;;;;;;;;;AAOA;;;;;;;;;;;;GAYG;AACH,MAAa,sBAAsB;IACjC,YACmB,MAAe,EACf,gBAAwB,IAAI;QAD5B,WAAM,GAAN,MAAM,CAAS;QACf,kBAAa,GAAb,aAAa,CAAe;IAC5C,CAAC;IAEJ;;OAEG;IACG,SAAS,CACb,OAAgC,EAChC,OAAqC,EACrC,WAAmB;;YAEnB,MAAM,SAAS,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC;YAEpC,IAAI,CAAC;gBACH,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,WAAW,CAAC,CAAC;gBAC1C,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC,CAAC;gBAE3D,mEAAmE;gBACnE,IAAI,QAAQ,IAAI,IAAI,CAAC,aAAa,EAAE,CAAC;oBACnC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,0BAA0B,EAAE;wBAC3C,SAAS,EAAE,OAAO,CAAC,SAAS;wBAC5B,WAAW,EAAE,OAAO,CAAC,WAAW;wBAChC,QAAQ;wBACR,SAAS,EAAE,IAAI,CAAC,aAAa;wBAC7B,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;qBACpC,CAAC,CAAC;gBACL,CAAC;gBAED,wCAAwC;gBACxC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,kBAAkB,EAAE;oBACpC,SAAS,EAAE,OAAO,CAAC,SAAS;oBAC5B,WAAW,EAAE,OAAO,CAAC,WAAW;oBAChC,UAAU,EAAE,OAAO,CAAC,UAAU;oBAC9B,SAAS,EAAE,OAAO,CAAC,SAAS;oBAC5B,QAAQ;oBACR,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;iBACpC,CAAC,CAAC;gBAEH,OAAO;oBACL,MAAM;oBACN,QAAQ;oBACR,OAAO,EAAE,IAAI;iBACd,CAAC;YACJ,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC,CAAC;gBAE3D,yDAAyD;gBACzD,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,2BAA2B,EAAE;oBAC7C,SAAS,EAAE,OAAO,CAAC,SAAS;oBAC5B,WAAW,EAAE,OAAO,CAAC,WAAW;oBAChC,QAAQ;oBACR,KAAK,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC;oBAC7D,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;iBACpC,CAAC,CAAC;gBAEH,OAAO;oBACL,MAAM,EAAE,SAAc;oBACtB,QAAQ;oBACR,OAAO,EAAE,KAAK;oBACd,KAAK,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;iBACjE,CAAC;YACJ,CAAC;QACH,CAAC;KAAA;CACF;AAlED,wDAkEC"}