pp-command-bus 1.5.0 → 2.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +400 -1219
- package/dist/command-bus/command-bus.spec.js +138 -359
- package/dist/command-bus/command-bus.spec.js.map +1 -1
- package/dist/command-bus/command.d.ts +3 -4
- package/dist/command-bus/command.js +3 -32
- package/dist/command-bus/command.js.map +1 -1
- package/dist/command-bus/config/command-bus-config.d.ts +80 -21
- package/dist/command-bus/config/command-bus-config.js +104 -58
- package/dist/command-bus/config/command-bus-config.js.map +1 -1
- package/dist/command-bus/config/command-bus-config.spec.js +174 -100
- package/dist/command-bus/config/command-bus-config.spec.js.map +1 -1
- package/dist/command-bus/index.d.ts +41 -50
- package/dist/command-bus/index.js +143 -127
- package/dist/command-bus/index.js.map +1 -1
- package/dist/command-bus/interceptors/index.d.ts +5 -0
- package/dist/command-bus/interceptors/index.js +22 -0
- package/dist/command-bus/interceptors/index.js.map +1 -0
- package/dist/command-bus/interceptors/interceptor.interface.d.ts +35 -0
- package/dist/command-bus/interceptors/interceptor.interface.js +3 -0
- package/dist/command-bus/interceptors/interceptor.interface.js.map +1 -0
- package/dist/command-bus/interceptors/performance-interceptor.d.ts +24 -0
- package/dist/command-bus/interceptors/performance-interceptor.js +86 -0
- package/dist/command-bus/interceptors/performance-interceptor.js.map +1 -0
- package/dist/command-bus/interceptors/performance-interceptor.spec.js +124 -0
- package/dist/command-bus/interceptors/performance-interceptor.spec.js.map +1 -0
- package/dist/command-bus/logging/command-logger.d.ts +2 -0
- package/dist/command-bus/logging/command-logger.js +7 -0
- package/dist/command-bus/logging/command-logger.js.map +1 -1
- package/dist/command-bus/logging/command-logger.spec.js +36 -0
- package/dist/command-bus/logging/command-logger.spec.js.map +1 -1
- package/dist/command-bus/serialization/index.d.ts +6 -0
- package/dist/command-bus/serialization/index.js +9 -0
- package/dist/command-bus/serialization/index.js.map +1 -0
- package/dist/command-bus/serialization/msgpack-serializer.d.ts +26 -0
- package/dist/command-bus/serialization/msgpack-serializer.js +70 -0
- package/dist/command-bus/serialization/msgpack-serializer.js.map +1 -0
- package/dist/command-bus/serialization/msgpack-serializer.spec.js +223 -0
- package/dist/command-bus/serialization/msgpack-serializer.spec.js.map +1 -0
- package/dist/command-bus/serialization/serializer.interface.d.ts +21 -0
- package/dist/command-bus/serialization/serializer.interface.js +3 -0
- package/dist/command-bus/serialization/serializer.interface.js.map +1 -0
- package/dist/command-bus/transport/consumer-loop.d.ts +45 -0
- package/dist/command-bus/transport/consumer-loop.js +90 -0
- package/dist/command-bus/transport/consumer-loop.js.map +1 -0
- package/dist/command-bus/transport/consumer-loop.spec.js +216 -0
- package/dist/command-bus/transport/consumer-loop.spec.js.map +1 -0
- package/dist/command-bus/transport/index.d.ts +21 -0
- package/dist/command-bus/transport/index.js +23 -0
- package/dist/command-bus/transport/index.js.map +1 -0
- package/dist/command-bus/transport/message-processor.d.ts +70 -0
- package/dist/command-bus/transport/message-processor.js +158 -0
- package/dist/command-bus/transport/message-processor.js.map +1 -0
- package/dist/command-bus/transport/message-processor.spec.js +185 -0
- package/dist/command-bus/transport/message-processor.spec.js.map +1 -0
- package/dist/command-bus/transport/pending-recovery.d.ts +54 -0
- package/dist/command-bus/transport/pending-recovery.js +139 -0
- package/dist/command-bus/transport/pending-recovery.js.map +1 -0
- package/dist/command-bus/transport/pending-recovery.spec.js +176 -0
- package/dist/command-bus/transport/pending-recovery.spec.js.map +1 -0
- package/dist/command-bus/transport/redis-codec.d.ts +24 -0
- package/dist/command-bus/transport/redis-codec.js +33 -0
- package/dist/command-bus/transport/redis-codec.js.map +1 -0
- package/dist/command-bus/transport/redis-codec.spec.js +53 -0
- package/dist/command-bus/transport/redis-codec.spec.js.map +1 -0
- package/dist/command-bus/transport/redis-streams-transport.d.ts +94 -0
- package/dist/command-bus/transport/redis-streams-transport.js +143 -0
- package/dist/command-bus/transport/redis-streams-transport.js.map +1 -0
- package/dist/command-bus/transport/redis-streams-transport.spec.js +420 -0
- package/dist/command-bus/transport/redis-streams-transport.spec.js.map +1 -0
- package/dist/command-bus/transport/rpc-handler.d.ts +39 -0
- package/dist/command-bus/transport/rpc-handler.js +87 -0
- package/dist/command-bus/transport/rpc-handler.js.map +1 -0
- package/dist/command-bus/transport/rpc-handler.spec.js +157 -0
- package/dist/command-bus/transport/rpc-handler.spec.js.map +1 -0
- package/dist/command-bus/transport/stream-consumer.d.ts +91 -0
- package/dist/command-bus/transport/stream-consumer.js +182 -0
- package/dist/command-bus/transport/stream-consumer.js.map +1 -0
- package/dist/command-bus/transport/stream-consumer.spec.js +284 -0
- package/dist/command-bus/transport/stream-consumer.spec.js.map +1 -0
- package/dist/command-bus/transport/stream-producer.d.ts +23 -0
- package/dist/command-bus/transport/stream-producer.js +70 -0
- package/dist/command-bus/transport/stream-producer.js.map +1 -0
- package/dist/command-bus/transport/stream-producer.spec.js +125 -0
- package/dist/command-bus/transport/stream-producer.spec.js.map +1 -0
- package/dist/command-bus/transport/transport.interface.d.ts +87 -0
- package/dist/command-bus/transport/transport.interface.js +3 -0
- package/dist/command-bus/transport/transport.interface.js.map +1 -0
- package/dist/command-bus/types/index.d.ts +0 -84
- package/dist/examples/rpc.demo.js +1 -1
- package/dist/examples/rpc.demo.js.map +1 -1
- package/dist/index.d.ts +8 -5
- package/dist/index.js +6 -4
- package/dist/index.js.map +1 -1
- package/dist/pp-command-bus-2.0.1.tgz +0 -0
- package/dist/shared/redis/connection-pool.d.ts +54 -0
- package/dist/shared/redis/connection-pool.js +123 -0
- package/dist/shared/redis/connection-pool.js.map +1 -0
- package/dist/shared/redis/connection-pool.spec.d.ts +1 -0
- package/dist/shared/redis/connection-pool.spec.js +114 -0
- package/dist/shared/redis/connection-pool.spec.js.map +1 -0
- package/dist/shared/redis/index.d.ts +5 -3
- package/dist/shared/redis/index.js +6 -4
- package/dist/shared/redis/index.js.map +1 -1
- package/dist/shared/redis/rpc-connection-pool.d.ts +61 -0
- package/dist/shared/redis/rpc-connection-pool.js +154 -0
- package/dist/shared/redis/rpc-connection-pool.js.map +1 -0
- package/dist/shared/redis/rpc-connection-pool.spec.d.ts +1 -0
- package/dist/shared/redis/rpc-connection-pool.spec.js +173 -0
- package/dist/shared/redis/rpc-connection-pool.spec.js.map +1 -0
- package/dist/shared/types.d.ts +0 -4
- package/dist/shared/utils/error-utils.d.ts +8 -0
- package/dist/shared/utils/error-utils.js +14 -0
- package/dist/shared/utils/error-utils.js.map +1 -0
- package/package.json +12 -12
- package/dist/command-bus/config/auto-config-optimizer.d.ts +0 -35
- package/dist/command-bus/config/auto-config-optimizer.js +0 -52
- package/dist/command-bus/config/auto-config-optimizer.js.map +0 -1
- package/dist/command-bus/config/auto-config-optimizer.spec.js +0 -42
- package/dist/command-bus/config/auto-config-optimizer.spec.js.map +0 -1
- package/dist/command-bus/job/index.d.ts +0 -6
- package/dist/command-bus/job/index.js +0 -15
- package/dist/command-bus/job/index.js.map +0 -1
- package/dist/command-bus/job/job-options-builder.d.ts +0 -21
- package/dist/command-bus/job/job-options-builder.js +0 -58
- package/dist/command-bus/job/job-options-builder.js.map +0 -1
- package/dist/command-bus/job/job-options-builder.spec.js +0 -156
- package/dist/command-bus/job/job-options-builder.spec.js.map +0 -1
- package/dist/command-bus/job/job-processor.d.ts +0 -39
- package/dist/command-bus/job/job-processor.js +0 -203
- package/dist/command-bus/job/job-processor.js.map +0 -1
- package/dist/command-bus/job/job-processor.spec.js +0 -436
- package/dist/command-bus/job/job-processor.spec.js.map +0 -1
- package/dist/command-bus/queue/index.d.ts +0 -5
- package/dist/command-bus/queue/index.js +0 -13
- package/dist/command-bus/queue/index.js.map +0 -1
- package/dist/command-bus/queue/queue-manager.d.ts +0 -56
- package/dist/command-bus/queue/queue-manager.js +0 -163
- package/dist/command-bus/queue/queue-manager.js.map +0 -1
- package/dist/command-bus/queue/queue-manager.spec.js +0 -371
- package/dist/command-bus/queue/queue-manager.spec.js.map +0 -1
- package/dist/command-bus/rpc/index.d.ts +0 -11
- package/dist/command-bus/rpc/index.js +0 -19
- package/dist/command-bus/rpc/index.js.map +0 -1
- package/dist/command-bus/rpc/payload-compression.service.d.ts +0 -50
- package/dist/command-bus/rpc/payload-compression.service.js +0 -215
- package/dist/command-bus/rpc/payload-compression.service.js.map +0 -1
- package/dist/command-bus/rpc/payload-compression.service.spec.js +0 -376
- package/dist/command-bus/rpc/payload-compression.service.spec.js.map +0 -1
- package/dist/command-bus/rpc/rpc-coordinator.d.ts +0 -96
- package/dist/command-bus/rpc/rpc-coordinator.js +0 -500
- package/dist/command-bus/rpc/rpc-coordinator.js.map +0 -1
- package/dist/command-bus/rpc/rpc-coordinator.spec.js +0 -621
- package/dist/command-bus/rpc/rpc-coordinator.spec.js.map +0 -1
- package/dist/command-bus/rpc/rpc-job-cancellation.service.d.ts +0 -82
- package/dist/command-bus/rpc/rpc-job-cancellation.service.js +0 -180
- package/dist/command-bus/rpc/rpc-job-cancellation.service.js.map +0 -1
- package/dist/command-bus/rpc/rpc-job-cancellation.service.spec.js +0 -286
- package/dist/command-bus/rpc/rpc-job-cancellation.service.spec.js.map +0 -1
- package/dist/command-bus/worker/index.d.ts +0 -10
- package/dist/command-bus/worker/index.js +0 -19
- package/dist/command-bus/worker/index.js.map +0 -1
- package/dist/command-bus/worker/worker-benchmark.d.ts +0 -71
- package/dist/command-bus/worker/worker-benchmark.js +0 -202
- package/dist/command-bus/worker/worker-benchmark.js.map +0 -1
- package/dist/command-bus/worker/worker-benchmark.spec.js +0 -310
- package/dist/command-bus/worker/worker-benchmark.spec.js.map +0 -1
- package/dist/command-bus/worker/worker-metrics-collector.d.ts +0 -98
- package/dist/command-bus/worker/worker-metrics-collector.js +0 -242
- package/dist/command-bus/worker/worker-metrics-collector.js.map +0 -1
- package/dist/command-bus/worker/worker-orchestrator.d.ts +0 -70
- package/dist/command-bus/worker/worker-orchestrator.js +0 -339
- package/dist/command-bus/worker/worker-orchestrator.js.map +0 -1
- package/dist/command-bus/worker/worker-orchestrator.spec.js +0 -712
- package/dist/command-bus/worker/worker-orchestrator.spec.js.map +0 -1
- package/dist/examples/auto-config.demo.d.ts +0 -9
- package/dist/examples/auto-config.demo.js +0 -106
- package/dist/examples/auto-config.demo.js.map +0 -1
- package/dist/examples/rpc-compression.demo.d.ts +0 -5
- package/dist/examples/rpc-compression.demo.js +0 -358
- package/dist/examples/rpc-compression.demo.js.map +0 -1
- package/dist/examples/rpc-resilience.demo.d.ts +0 -15
- package/dist/examples/rpc-resilience.demo.js +0 -233
- package/dist/examples/rpc-resilience.demo.js.map +0 -1
- package/dist/pp-command-bus-1.5.0.tgz +0 -0
- package/dist/shared/config/base-config.d.ts +0 -54
- package/dist/shared/config/base-config.js +0 -114
- package/dist/shared/config/base-config.js.map +0 -1
- package/dist/shared/config/base-config.spec.js +0 -204
- package/dist/shared/config/base-config.spec.js.map +0 -1
- package/dist/shared/config/index.d.ts +0 -1
- package/dist/shared/config/index.js +0 -9
- package/dist/shared/config/index.js.map +0 -1
- package/dist/shared/redis/redis-connection-factory.d.ts +0 -66
- package/dist/shared/redis/redis-connection-factory.js +0 -113
- package/dist/shared/redis/redis-connection-factory.js.map +0 -1
- /package/dist/command-bus/{config/auto-config-optimizer.spec.d.ts → interceptors/performance-interceptor.spec.d.ts} +0 -0
- /package/dist/command-bus/{job/job-options-builder.spec.d.ts → serialization/msgpack-serializer.spec.d.ts} +0 -0
- /package/dist/command-bus/{job/job-processor.spec.d.ts → transport/consumer-loop.spec.d.ts} +0 -0
- /package/dist/command-bus/{queue/queue-manager.spec.d.ts → transport/message-processor.spec.d.ts} +0 -0
- /package/dist/command-bus/{rpc/payload-compression.service.spec.d.ts → transport/pending-recovery.spec.d.ts} +0 -0
- /package/dist/command-bus/{rpc/rpc-coordinator.spec.d.ts → transport/redis-codec.spec.d.ts} +0 -0
- /package/dist/command-bus/{rpc/rpc-job-cancellation.service.spec.d.ts → transport/redis-streams-transport.spec.d.ts} +0 -0
- /package/dist/command-bus/{worker/worker-benchmark.spec.d.ts → transport/rpc-handler.spec.d.ts} +0 -0
- /package/dist/command-bus/{worker/worker-orchestrator.spec.d.ts → transport/stream-consumer.spec.d.ts} +0 -0
- /package/dist/{shared/config/base-config.spec.d.ts → command-bus/transport/stream-producer.spec.d.ts} +0 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Interfejs serializera dla CommandBus
|
|
3
|
+
* Odpowiada za konwersję danych do/z formatu binarnego (Buffer)
|
|
4
|
+
*
|
|
5
|
+
* Implementacje powinny obsługiwać natywne typy JS (Date, Buffer, nested objects)
|
|
6
|
+
* bez konieczności dodatkowej rekonstrukcji typów po deserializacji
|
|
7
|
+
*/
|
|
8
|
+
export interface ISerializer {
|
|
9
|
+
/**
|
|
10
|
+
* Serializuje dane do formatu binarnego
|
|
11
|
+
* @param data - Dane do serializacji
|
|
12
|
+
* @returns Buffer z serializowanymi danymi
|
|
13
|
+
*/
|
|
14
|
+
serialize(data: unknown): Buffer;
|
|
15
|
+
/**
|
|
16
|
+
* Deserializuje dane z formatu binarnego
|
|
17
|
+
* @param buffer - Buffer z serializowanymi danymi
|
|
18
|
+
* @returns Zdeserializowane dane
|
|
19
|
+
*/
|
|
20
|
+
deserialize<T>(buffer: Buffer): T;
|
|
21
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"serializer.interface.js","sourceRoot":"","sources":["../../../src/command-bus/serialization/serializer.interface.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { Redis } from 'ioredis';
|
|
2
|
+
import type { ILogger } from '../../shared/types';
|
|
3
|
+
/**
|
|
4
|
+
* Callback wywoływany dla każdej wiadomości odczytanej ze strumienia
|
|
5
|
+
*/
|
|
6
|
+
export type MessageCallback = (messageId: string, fields: string[]) => Promise<void>;
|
|
7
|
+
/**
|
|
8
|
+
* Konfiguracja ConsumerLoop
|
|
9
|
+
*/
|
|
10
|
+
export interface ConsumerLoopOptions {
|
|
11
|
+
consumerId: string;
|
|
12
|
+
batchSize: number;
|
|
13
|
+
concurrency: number;
|
|
14
|
+
logger: ILogger;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Consumer loop — czyta wiadomości z Redis Streams i przekazuje do callbacka
|
|
18
|
+
*
|
|
19
|
+
* Odpowiedzialności:
|
|
20
|
+
* - while(running) loop z XREADGROUP BLOCK
|
|
21
|
+
* - Concurrency limiter (Promise.race + active Set)
|
|
22
|
+
* - Exponential backoff z jitter przy błędach
|
|
23
|
+
* - Czekanie na aktywne zadania przy shutdown
|
|
24
|
+
*
|
|
25
|
+
* NIE odpowiada za przetwarzanie wiadomości — to odpowiedzialność koordynatora/procesora
|
|
26
|
+
*/
|
|
27
|
+
export declare class ConsumerLoop {
|
|
28
|
+
private readonly consumerId;
|
|
29
|
+
private readonly batchSize;
|
|
30
|
+
private readonly concurrency;
|
|
31
|
+
private readonly logger;
|
|
32
|
+
/** Flaga zatrzymania consumer loop */
|
|
33
|
+
running: boolean;
|
|
34
|
+
constructor(options: ConsumerLoopOptions);
|
|
35
|
+
/**
|
|
36
|
+
* Uruchamia consumer loop — czyta wiadomości z strumienia i przetwarza
|
|
37
|
+
* Concurrency limiter: przetwarza N wiadomości równolegle, czyta gdy wolne sloty
|
|
38
|
+
*
|
|
39
|
+
* @param conn - Dedykowane połączenie Redis (XREADGROUP BLOCK blokuje socket)
|
|
40
|
+
* @param streamName - Nazwa strumienia Redis
|
|
41
|
+
* @param groupName - Nazwa grupy konsumentów
|
|
42
|
+
* @param onMessage - Callback wywoływany dla każdej wiadomości
|
|
43
|
+
*/
|
|
44
|
+
run(conn: Redis, streamName: string, groupName: string, onMessage: MessageCallback): Promise<void>;
|
|
45
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
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.ConsumerLoop = void 0;
|
|
13
|
+
const error_utils_1 = require("../../shared/utils/error-utils");
|
|
14
|
+
/**
|
|
15
|
+
* Consumer loop — czyta wiadomości z Redis Streams i przekazuje do callbacka
|
|
16
|
+
*
|
|
17
|
+
* Odpowiedzialności:
|
|
18
|
+
* - while(running) loop z XREADGROUP BLOCK
|
|
19
|
+
* - Concurrency limiter (Promise.race + active Set)
|
|
20
|
+
* - Exponential backoff z jitter przy błędach
|
|
21
|
+
* - Czekanie na aktywne zadania przy shutdown
|
|
22
|
+
*
|
|
23
|
+
* NIE odpowiada za przetwarzanie wiadomości — to odpowiedzialność koordynatora/procesora
|
|
24
|
+
*/
|
|
25
|
+
class ConsumerLoop {
|
|
26
|
+
constructor(options) {
|
|
27
|
+
/** Flaga zatrzymania consumer loop */
|
|
28
|
+
this.running = true;
|
|
29
|
+
this.consumerId = options.consumerId;
|
|
30
|
+
this.batchSize = options.batchSize;
|
|
31
|
+
this.concurrency = options.concurrency;
|
|
32
|
+
this.logger = options.logger;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Uruchamia consumer loop — czyta wiadomości z strumienia i przetwarza
|
|
36
|
+
* Concurrency limiter: przetwarza N wiadomości równolegle, czyta gdy wolne sloty
|
|
37
|
+
*
|
|
38
|
+
* @param conn - Dedykowane połączenie Redis (XREADGROUP BLOCK blokuje socket)
|
|
39
|
+
* @param streamName - Nazwa strumienia Redis
|
|
40
|
+
* @param groupName - Nazwa grupy konsumentów
|
|
41
|
+
* @param onMessage - Callback wywoływany dla każdej wiadomości
|
|
42
|
+
*/
|
|
43
|
+
run(conn, streamName, groupName, onMessage) {
|
|
44
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
45
|
+
const active = new Set();
|
|
46
|
+
let consecutiveErrors = 0;
|
|
47
|
+
while (this.running) {
|
|
48
|
+
try {
|
|
49
|
+
while (active.size >= this.concurrency && this.running) {
|
|
50
|
+
yield Promise.race(active);
|
|
51
|
+
}
|
|
52
|
+
if (!this.running)
|
|
53
|
+
break;
|
|
54
|
+
const availableSlots = this.concurrency - active.size;
|
|
55
|
+
const count = Math.min(this.batchSize, availableSlots);
|
|
56
|
+
const result = yield conn.xreadgroup('GROUP', groupName, this.consumerId, 'COUNT', count, 'BLOCK', 5000, 'STREAMS', streamName, '>');
|
|
57
|
+
consecutiveErrors = 0;
|
|
58
|
+
if (!result)
|
|
59
|
+
continue;
|
|
60
|
+
const messages = result;
|
|
61
|
+
for (const [, streamMessages] of messages) {
|
|
62
|
+
for (const [messageId, fields] of streamMessages) {
|
|
63
|
+
const processing = onMessage(messageId, fields);
|
|
64
|
+
active.add(processing);
|
|
65
|
+
void processing.finally(() => active.delete(processing));
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
catch (error) {
|
|
70
|
+
if (!this.running)
|
|
71
|
+
break;
|
|
72
|
+
consecutiveErrors++;
|
|
73
|
+
this.logger.error('Błąd w consumer loop', {
|
|
74
|
+
streamName,
|
|
75
|
+
error: (0, error_utils_1.getErrorMessage)(error),
|
|
76
|
+
consecutiveErrors,
|
|
77
|
+
timestamp: new Date().toISOString(),
|
|
78
|
+
});
|
|
79
|
+
const backoff = Math.min(1000 * Math.pow(2, consecutiveErrors - 1), 30000) + Math.random() * 1000;
|
|
80
|
+
yield new Promise((r) => setTimeout(r, backoff));
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
if (active.size > 0) {
|
|
84
|
+
yield Promise.allSettled(active);
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
exports.ConsumerLoop = ConsumerLoop;
|
|
90
|
+
//# sourceMappingURL=consumer-loop.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"consumer-loop.js","sourceRoot":"","sources":["../../../src/command-bus/transport/consumer-loop.ts"],"names":[],"mappings":"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"}
|
|
@@ -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,70 @@
|
|
|
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
|
+
import type { ICommandInterceptor } from '../interceptors';
|
|
6
|
+
/**
|
|
7
|
+
* Typ callbacka do wysyłania odpowiedzi RPC
|
|
8
|
+
*/
|
|
9
|
+
export type RpcResponder = (responseKey: string, data: Buffer, ttl: number) => Promise<void>;
|
|
10
|
+
/**
|
|
11
|
+
* Konfiguracja MessageProcessor
|
|
12
|
+
*/
|
|
13
|
+
export interface MessageProcessorOptions {
|
|
14
|
+
pool: RedisConnectionPool;
|
|
15
|
+
serializer: ISerializer;
|
|
16
|
+
logger: ILogger;
|
|
17
|
+
batchSize: number;
|
|
18
|
+
maxRetained: number;
|
|
19
|
+
rpcRespond: RpcResponder;
|
|
20
|
+
interceptor?: ICommandInterceptor;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Procesor wiadomości — parsuje, waliduje, przetwarza i potwierdza wiadomości
|
|
24
|
+
*
|
|
25
|
+
* Odpowiedzialności:
|
|
26
|
+
* - Parsowanie fields → fieldMap
|
|
27
|
+
* - Walidacja danych wejściowych (H4)
|
|
28
|
+
* - Detekcja RPC via marker field
|
|
29
|
+
* - Wywołanie handlera
|
|
30
|
+
* - XACK + throttled XTRIM (H2: per-stream counters)
|
|
31
|
+
* - Wysyłanie odpowiedzi RPC
|
|
32
|
+
*
|
|
33
|
+
* NIE odpowiada za deduplicację — to odpowiedzialność koordynatora (StreamConsumer)
|
|
34
|
+
*/
|
|
35
|
+
export declare class MessageProcessor {
|
|
36
|
+
private readonly pool;
|
|
37
|
+
private readonly serializer;
|
|
38
|
+
private readonly logger;
|
|
39
|
+
private readonly batchSize;
|
|
40
|
+
private readonly maxRetained;
|
|
41
|
+
private readonly rpcRespond;
|
|
42
|
+
private readonly interceptor?;
|
|
43
|
+
/** H2: Liczniki wiadomości od ostatniego XTRIM — per strumień */
|
|
44
|
+
private readonly xtrimCounters;
|
|
45
|
+
constructor(options: MessageProcessorOptions);
|
|
46
|
+
/**
|
|
47
|
+
* Czyści stan counters — wywoływane przy close()
|
|
48
|
+
*/
|
|
49
|
+
reset(): void;
|
|
50
|
+
/**
|
|
51
|
+
* Przetwarza wiadomość — parsuje fields, wykrywa RPC, wywołuje handler, XACK/XTRIM
|
|
52
|
+
*
|
|
53
|
+
* Błędy propagują do callera (koordynatora) — nie łapie wewnętrznie
|
|
54
|
+
*
|
|
55
|
+
* @param streamName - Nazwa strumienia Redis
|
|
56
|
+
* @param groupName - Nazwa grupy konsumentów
|
|
57
|
+
* @param messageId - ID wiadomości
|
|
58
|
+
* @param fields - Tablica pól ze strumienia [key, value, key, value, ...]
|
|
59
|
+
* @param handler - Handler przetwarzający dane komendy
|
|
60
|
+
*/
|
|
61
|
+
process(streamName: string, groupName: string, messageId: string, fields: string[], handler: ConsumerHandler): Promise<void>;
|
|
62
|
+
/**
|
|
63
|
+
* Ekstrakcja commandId z commandData (deserializacja metadata)
|
|
64
|
+
*/
|
|
65
|
+
private extractCommandId;
|
|
66
|
+
/**
|
|
67
|
+
* Ekstrakcja nazwy komendy ze streamName (usunięcie prefiksu 'cmd:')
|
|
68
|
+
*/
|
|
69
|
+
private extractCommandName;
|
|
70
|
+
}
|