@volontariapp/post-processors 1.0.0-snap-fb20f49 → 1.0.0-snap-678b8d1

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 (62) hide show
  1. package/dist/core/processors/base.post-processor.d.ts +1 -0
  2. package/dist/core/processors/base.post-processor.d.ts.map +1 -1
  3. package/dist/core/processors/base.post-processor.js +3 -0
  4. package/dist/core/processors/base.post-processor.js.map +1 -1
  5. package/dist/test/data-source.d.ts.map +1 -1
  6. package/dist/test/data-source.js +4 -12
  7. package/dist/test/data-source.js.map +1 -1
  8. package/dist/test/specs/integration/batch-post-processor-e2e.int.spec.d.ts +2 -0
  9. package/dist/test/specs/integration/batch-post-processor-e2e.int.spec.d.ts.map +1 -0
  10. package/dist/test/specs/integration/batch-post-processor-e2e.int.spec.js +190 -0
  11. package/dist/test/specs/integration/batch-post-processor-e2e.int.spec.js.map +1 -0
  12. package/dist/test/specs/integration/circuit-breaker.integration.spec.js +45 -17
  13. package/dist/test/specs/integration/circuit-breaker.integration.spec.js.map +1 -1
  14. package/dist/test/specs/integration/multiple-post-processors.int.spec.d.ts +2 -0
  15. package/dist/test/specs/integration/multiple-post-processors.int.spec.d.ts.map +1 -0
  16. package/dist/test/specs/integration/multiple-post-processors.int.spec.js +247 -0
  17. package/dist/test/specs/integration/multiple-post-processors.int.spec.js.map +1 -0
  18. package/dist/test/specs/integration/single-post-processor-e2e.int.spec.d.ts +2 -0
  19. package/dist/test/specs/integration/single-post-processor-e2e.int.spec.d.ts.map +1 -0
  20. package/dist/test/specs/integration/single-post-processor-e2e.int.spec.js +288 -0
  21. package/dist/test/specs/integration/single-post-processor-e2e.int.spec.js.map +1 -0
  22. package/dist/test/utils/classes/e2e-batch-post-processor.class.d.ts +14 -0
  23. package/dist/test/utils/classes/e2e-batch-post-processor.class.d.ts.map +1 -0
  24. package/dist/test/utils/classes/e2e-batch-post-processor.class.js +34 -0
  25. package/dist/test/utils/classes/e2e-batch-post-processor.class.js.map +1 -0
  26. package/dist/test/utils/classes/e2e-single-post-processor.class.d.ts +16 -0
  27. package/dist/test/utils/classes/e2e-single-post-processor.class.d.ts.map +1 -0
  28. package/dist/test/utils/classes/e2e-single-post-processor.class.js +27 -0
  29. package/dist/test/utils/classes/e2e-single-post-processor.class.js.map +1 -0
  30. package/dist/test/utils/classes/test-base-post-processor.class.d.ts +23 -0
  31. package/dist/test/utils/classes/test-base-post-processor.class.d.ts.map +1 -0
  32. package/dist/test/utils/classes/test-base-post-processor.class.js +60 -0
  33. package/dist/test/utils/classes/test-base-post-processor.class.js.map +1 -0
  34. package/dist/test/utils/classes/test-batch-post-processor.class.d.ts +1 -0
  35. package/dist/test/utils/classes/test-batch-post-processor.class.d.ts.map +1 -1
  36. package/dist/test/utils/classes/test-batch-post-processor.class.js +3 -0
  37. package/dist/test/utils/classes/test-batch-post-processor.class.js.map +1 -1
  38. package/dist/test/utils/classes/test-post-processor.class.d.ts +1 -0
  39. package/dist/test/utils/classes/test-post-processor.class.d.ts.map +1 -1
  40. package/dist/test/utils/classes/test-post-processor.class.js +3 -0
  41. package/dist/test/utils/classes/test-post-processor.class.js.map +1 -1
  42. package/dist/test/utils/factories/test-event.factory.d.ts +4 -0
  43. package/dist/test/utils/factories/test-event.factory.d.ts.map +1 -1
  44. package/dist/test/utils/factories/test-event.factory.js +30 -0
  45. package/dist/test/utils/factories/test-event.factory.js.map +1 -1
  46. package/dist/test/utils/helpers/push-db-event.helper.d.ts +12 -0
  47. package/dist/test/utils/helpers/push-db-event.helper.d.ts.map +1 -0
  48. package/dist/test/utils/helpers/push-db-event.helper.js +36 -0
  49. package/dist/test/utils/helpers/push-db-event.helper.js.map +1 -0
  50. package/dist/test/utils/index.d.ts +4 -0
  51. package/dist/test/utils/index.d.ts.map +1 -1
  52. package/dist/test/utils/index.js +4 -0
  53. package/dist/test/utils/index.js.map +1 -1
  54. package/package.json +6 -5
  55. package/dist/test/migrations/1776783577425-CreateJobsOutbox.d.ts +0 -7
  56. package/dist/test/migrations/1776783577425-CreateJobsOutbox.d.ts.map +0 -1
  57. package/dist/test/migrations/1776783577425-CreateJobsOutbox.js +0 -25
  58. package/dist/test/migrations/1776783577425-CreateJobsOutbox.js.map +0 -1
  59. package/dist/test/migrations/1778328780881-InitialSchemaJobAudit.d.ts +0 -6
  60. package/dist/test/migrations/1778328780881-InitialSchemaJobAudit.d.ts.map +0 -1
  61. package/dist/test/migrations/1778328780881-InitialSchemaJobAudit.js +0 -93
  62. package/dist/test/migrations/1778328780881-InitialSchemaJobAudit.js.map +0 -1
@@ -0,0 +1,247 @@
1
+ import { describe, it, expect, beforeEach, afterEach, beforeAll, afterAll } from '@jest/globals';
2
+ import { Redis } from 'ioredis';
3
+ import { databaseMapper, EventQueueModel, EventQueueEntity } from '@volontariapp/database';
4
+ import { Logger } from '@volontariapp/logger';
5
+ import { testDataSource, initializeTestDb, closeTestDb } from '../../data-source.js';
6
+ import { testRedisOptions } from '../../redis-config.js';
7
+ import { E2ESinglePostProcessor, pushDbEvent, startOutboxLoop, waitFor, } from '../../utils/index.js';
8
+ describe('Multiple Post-Processors E2E Integration Flow', () => {
9
+ let redis;
10
+ let repository;
11
+ let outboxInterval = null;
12
+ const testLogger = new Logger({ context: 'E2E-Multiple' });
13
+ const processors = [];
14
+ beforeAll(async () => {
15
+ await initializeTestDb();
16
+ databaseMapper.registerBidirectional(EventQueueModel, EventQueueEntity);
17
+ repository = testDataSource.getRepository(EventQueueModel);
18
+ redis = new Redis(testRedisOptions);
19
+ });
20
+ afterAll(async () => {
21
+ await redis.quit().catch(() => undefined);
22
+ await closeTestDb().catch(() => undefined);
23
+ });
24
+ beforeEach(async () => {
25
+ await repository.createQueryBuilder().delete().execute();
26
+ await redis.flushdb();
27
+ outboxInterval = startOutboxLoop(repository, redis, testLogger);
28
+ });
29
+ afterEach(async () => {
30
+ if (outboxInterval) {
31
+ clearInterval(outboxInterval);
32
+ outboxInterval = null;
33
+ }
34
+ for (const processor of processors) {
35
+ await processor.stop().catch(() => undefined);
36
+ }
37
+ processors.length = 0;
38
+ });
39
+ it('should support multiple consumer groups consuming the same stream independently', async () => {
40
+ const streamName = 'stream:shared-service';
41
+ const processorA = new E2ESinglePostProcessor(redis, {
42
+ streamName,
43
+ groupName: 'group:service-a',
44
+ consumerName: 'consumer:a-1',
45
+ claimIntervalMs: 100,
46
+ claimMinIdleTimeMs: 100,
47
+ blockMs: 50,
48
+ });
49
+ processors.push(processorA);
50
+ const processorB = new E2ESinglePostProcessor(redis, {
51
+ streamName,
52
+ groupName: 'group:service-b',
53
+ consumerName: 'consumer:b-1',
54
+ claimIntervalMs: 100,
55
+ claimMinIdleTimeMs: 100,
56
+ blockMs: 50,
57
+ });
58
+ processors.push(processorB);
59
+ for (let i = 1; i <= 5; i++) {
60
+ const eventId = `00000000-0000-0000-0000-00000000000${String(i)}`;
61
+ await pushDbEvent(repository, redis, testLogger, eventId, 'event.changed', [
62
+ 'shared-service',
63
+ ]);
64
+ }
65
+ await processorA.start();
66
+ await processorB.start();
67
+ await waitFor(() => {
68
+ return processorA.processedEvents.length === 5 && processorB.processedEvents.length === 5;
69
+ }, 5000);
70
+ expect(processorA.processedEvents.length).toBe(5);
71
+ expect(processorB.processedEvents.length).toBe(5);
72
+ const idsA = processorA.processedEvents.map((e) => e.event.id).sort();
73
+ const idsB = processorB.processedEvents.map((e) => e.event.id).sort();
74
+ expect(idsA).toEqual(idsB);
75
+ });
76
+ it('should load balance correctly with three competing consumers in the same group', async () => {
77
+ const streamName = 'stream:shared-service';
78
+ const groupName = 'group:competing-e2e';
79
+ const p1 = new E2ESinglePostProcessor(redis, {
80
+ streamName,
81
+ groupName,
82
+ consumerName: 'consumer:c-1',
83
+ claimIntervalMs: 100,
84
+ claimMinIdleTimeMs: 100,
85
+ blockMs: 50,
86
+ });
87
+ processors.push(p1);
88
+ const p2 = new E2ESinglePostProcessor(redis, {
89
+ streamName,
90
+ groupName,
91
+ consumerName: 'consumer:c-2',
92
+ claimIntervalMs: 100,
93
+ claimMinIdleTimeMs: 100,
94
+ blockMs: 50,
95
+ });
96
+ processors.push(p2);
97
+ const p3 = new E2ESinglePostProcessor(redis, {
98
+ streamName,
99
+ groupName,
100
+ consumerName: 'consumer:c-3',
101
+ claimIntervalMs: 100,
102
+ claimMinIdleTimeMs: 100,
103
+ blockMs: 50,
104
+ });
105
+ processors.push(p3);
106
+ for (let i = 1; i <= 12; i++) {
107
+ const eventId = `00000000-0000-0000-0000-0000000000${(10 + i).toString()}`;
108
+ await pushDbEvent(repository, redis, testLogger, eventId, 'event.changed', [
109
+ 'shared-service',
110
+ ]);
111
+ }
112
+ await p1.start();
113
+ await p2.start();
114
+ await p3.start();
115
+ await waitFor(() => {
116
+ const total = p1.processedEvents.length + p2.processedEvents.length + p3.processedEvents.length;
117
+ return total === 12;
118
+ }, 6000);
119
+ expect(p1.processedEvents.length + p2.processedEvents.length + p3.processedEvents.length).toBe(12);
120
+ const allIds = [
121
+ ...p1.processedEvents.map((e) => e.event.id),
122
+ ...p2.processedEvents.map((e) => e.event.id),
123
+ ...p3.processedEvents.map((e) => e.event.id),
124
+ ];
125
+ expect(new Set(allIds).size).toBe(12);
126
+ });
127
+ it('should support pending claim execution when one of the consumers crashes', async () => {
128
+ const streamName = 'stream:shared-service';
129
+ const groupName = 'group:claim-e2e';
130
+ const slowProcessor = new E2ESinglePostProcessor(redis, {
131
+ streamName,
132
+ groupName,
133
+ consumerName: 'consumer:slow-1',
134
+ claimIntervalMs: 5000,
135
+ claimMinIdleTimeMs: 5000,
136
+ blockMs: 50,
137
+ });
138
+ processors.push(slowProcessor);
139
+ const claimProcessor = new E2ESinglePostProcessor(redis, {
140
+ streamName,
141
+ groupName,
142
+ consumerName: 'consumer:claim-1',
143
+ claimIntervalMs: 50,
144
+ claimMinIdleTimeMs: 100,
145
+ blockMs: 50,
146
+ });
147
+ processors.push(claimProcessor);
148
+ const eventId = '00000000-0000-0000-0000-000000000030';
149
+ await pushDbEvent(repository, redis, testLogger, eventId, 'event.changed', [
150
+ 'shared-service',
151
+ ]);
152
+ slowProcessor.processError = new Error('Simulated slow crash');
153
+ await slowProcessor.start();
154
+ await waitFor(async () => {
155
+ const pending = await redis.xpending(streamName, groupName, '-', '+', 10);
156
+ return pending.length === 1;
157
+ }, 5000);
158
+ await slowProcessor.stop();
159
+ await new Promise((resolve) => setTimeout(resolve, 200));
160
+ await claimProcessor.start();
161
+ await waitFor(() => claimProcessor.processedEvents.length === 1, 5000);
162
+ expect(claimProcessor.processedEvents[0].event.id).toBe(eventId);
163
+ });
164
+ it('should isolate failures so that one failing group does not affect another succeeding group, routing to DLQ', async () => {
165
+ const streamName = 'stream:shared-service';
166
+ const failingProcessor = new E2ESinglePostProcessor(redis, {
167
+ streamName,
168
+ groupName: 'group:fail-group',
169
+ consumerName: 'consumer:fail-1',
170
+ claimIntervalMs: 100,
171
+ claimMinIdleTimeMs: 100,
172
+ blockMs: 50,
173
+ retry: {
174
+ maxRetries: 0,
175
+ initialDelayMs: 50,
176
+ maxDelayMs: 100,
177
+ backoffMultiplier: 1.5,
178
+ enableDlq: true,
179
+ },
180
+ });
181
+ processors.push(failingProcessor);
182
+ const succeedingProcessor = new E2ESinglePostProcessor(redis, {
183
+ streamName,
184
+ groupName: 'group:success-group',
185
+ consumerName: 'consumer:success-1',
186
+ claimIntervalMs: 100,
187
+ claimMinIdleTimeMs: 100,
188
+ blockMs: 50,
189
+ });
190
+ processors.push(succeedingProcessor);
191
+ const eventId = '00000000-0000-0000-0000-000000000040';
192
+ await pushDbEvent(repository, redis, testLogger, eventId, 'event.changed', [
193
+ 'shared-service',
194
+ ]);
195
+ failingProcessor.processError = new Error('Persistent failure for FailGroup');
196
+ await failingProcessor.start();
197
+ await succeedingProcessor.start();
198
+ await waitFor(() => succeedingProcessor.processedEvents.length === 1, 5000);
199
+ expect(succeedingProcessor.processedEvents[0].event.id).toBe(eventId);
200
+ const dlqStreamName = 'stream:shared-service-dlq';
201
+ await waitFor(async () => {
202
+ const xrange = await redis.xrange(dlqStreamName, '-', '+');
203
+ return xrange.length === 1;
204
+ }, 5000);
205
+ expect(failingProcessor.processedEvents.length).toBe(0);
206
+ const xrange = await redis.xrange(dlqStreamName, '-', '+');
207
+ const dlqFields = xrange[0][1];
208
+ const dlqObj = {};
209
+ for (let i = 0; i < dlqFields.length; i += 2) {
210
+ dlqObj[dlqFields[i]] = dlqFields[i + 1];
211
+ }
212
+ expect(dlqObj.error).toContain('Persistent failure for FailGroup');
213
+ });
214
+ it('should push a job to outbox, route it to multiple target streams, and process them with multiple post-processors', async () => {
215
+ const processorA = new E2ESinglePostProcessor(redis, {
216
+ streamName: 'stream:service-a',
217
+ groupName: 'group:service-a-e2e',
218
+ consumerName: 'consumer:a-1',
219
+ claimIntervalMs: 100,
220
+ claimMinIdleTimeMs: 100,
221
+ blockMs: 50,
222
+ });
223
+ processors.push(processorA);
224
+ const processorB = new E2ESinglePostProcessor(redis, {
225
+ streamName: 'stream:service-b',
226
+ groupName: 'group:service-b-e2e',
227
+ consumerName: 'consumer:b-1',
228
+ claimIntervalMs: 100,
229
+ claimMinIdleTimeMs: 100,
230
+ blockMs: 50,
231
+ });
232
+ processors.push(processorB);
233
+ const eventId = '00000000-0000-0000-0000-000000000050';
234
+ await pushDbEvent(repository, redis, testLogger, eventId, 'event.changed', [
235
+ 'service-a',
236
+ 'service-b',
237
+ ]);
238
+ await processorA.start();
239
+ await processorB.start();
240
+ await waitFor(() => {
241
+ return processorA.processedEvents.length === 1 && processorB.processedEvents.length === 1;
242
+ }, 5000);
243
+ expect(processorA.processedEvents[0].event.id).toBe(eventId);
244
+ expect(processorB.processedEvents[0].event.id).toBe(eventId);
245
+ });
246
+ });
247
+ //# sourceMappingURL=multiple-post-processors.int.spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"multiple-post-processors.int.spec.js","sourceRoot":"","sources":["../../../../src/test/specs/integration/multiple-post-processors.int.spec.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=single-post-processor-e2e.int.spec.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"single-post-processor-e2e.int.spec.d.ts","sourceRoot":"","sources":["../../../../src/test/specs/integration/single-post-processor-e2e.int.spec.ts"],"names":[],"mappings":""}
@@ -0,0 +1,288 @@
1
+ import { describe, it, expect, beforeEach, afterEach, beforeAll, afterAll, jest, } from '@jest/globals';
2
+ import { Redis } from 'ioredis';
3
+ import { databaseMapper, EventQueueModel, EventQueueEntity, OutboxStatus, } from '@volontariapp/database';
4
+ import { Logger } from '@volontariapp/logger';
5
+ import { testDataSource, initializeTestDb, closeTestDb } from '../../data-source.js';
6
+ import { testRedisOptions } from '../../redis-config.js';
7
+ import { E2ESinglePostProcessor, pushDbEvent, waitFor } from '../../utils/index.js';
8
+ import { CircuitBreakerState } from '../../../enums/circuit-breaker-state.enum.js';
9
+ describe('SinglePostProcessor E2E Integration Flow', () => {
10
+ let redis;
11
+ let repository;
12
+ let processor;
13
+ const testLogger = new Logger({ context: 'E2E-Single' });
14
+ beforeAll(async () => {
15
+ await initializeTestDb();
16
+ databaseMapper.registerBidirectional(EventQueueModel, EventQueueEntity);
17
+ repository = testDataSource.getRepository(EventQueueModel);
18
+ redis = new Redis(testRedisOptions);
19
+ });
20
+ afterAll(async () => {
21
+ await redis.quit().catch(() => undefined);
22
+ await closeTestDb().catch(() => undefined);
23
+ });
24
+ beforeEach(async () => {
25
+ await repository.createQueryBuilder().delete().execute();
26
+ await redis.flushdb();
27
+ jest.clearAllMocks();
28
+ });
29
+ afterEach(async () => {
30
+ await processor.stop();
31
+ });
32
+ it('should process a pending event end-to-end from Postgres outbox table', async () => {
33
+ processor = new E2ESinglePostProcessor(redis, {
34
+ streamName: 'stream:single-service',
35
+ groupName: 'group:single-e2e',
36
+ consumerName: 'consumer:single-e2e-1',
37
+ claimIntervalMs: 100,
38
+ claimMinIdleTimeMs: 100,
39
+ blockMs: 50,
40
+ });
41
+ const eventId = '00000000-0000-0000-0000-000000000001';
42
+ await pushDbEvent(repository, redis, testLogger, eventId, 'event.changed', [
43
+ 'single-service',
44
+ ]);
45
+ await processor.start();
46
+ await waitFor(() => processor.processedEvents.length === 1, 3000);
47
+ expect(processor.processedEvents[0].event.id).toBe(eventId);
48
+ expect(processor.processedEvents[0].event.type).toBe('event.changed');
49
+ const dbItem = await repository.findOneByOrFail({ id: eventId });
50
+ expect(dbItem.status).toBe(OutboxStatus.COMPLETED);
51
+ });
52
+ it('should retry a failed message with exponential backoff and then succeed', async () => {
53
+ processor = new E2ESinglePostProcessor(redis, {
54
+ streamName: 'stream:single-service',
55
+ groupName: 'group:single-e2e',
56
+ consumerName: 'consumer:single-e2e-1',
57
+ claimIntervalMs: 100,
58
+ claimMinIdleTimeMs: 50,
59
+ blockMs: 50,
60
+ retry: {
61
+ maxRetries: 3,
62
+ initialDelayMs: 100,
63
+ maxDelayMs: 1000,
64
+ backoffMultiplier: 2,
65
+ enableDlq: true,
66
+ },
67
+ });
68
+ const eventId = '00000000-0000-0000-0000-000000000002';
69
+ await pushDbEvent(repository, redis, testLogger, eventId, 'event.changed', [
70
+ 'single-service',
71
+ ]);
72
+ processor.processError = new Error('Transient database error');
73
+ await processor.start();
74
+ const retryQueueKey = 'retry-queue:post-processor:group:single-e2e';
75
+ await waitFor(async () => {
76
+ const zcard = await redis.zcard(retryQueueKey);
77
+ return zcard === 1;
78
+ }, 3000);
79
+ expect(processor.processedEvents.length).toBe(0);
80
+ processor.processError = null;
81
+ await waitFor(() => processor.processedEvents.length === 1, 3000);
82
+ expect(processor.processedEvents[0].event.id).toBe(eventId);
83
+ const zcardFinal = await redis.zcard(retryQueueKey);
84
+ expect(zcardFinal).toBe(0);
85
+ });
86
+ it('should send the message to DLQ stream after max retries are exceeded', async () => {
87
+ processor = new E2ESinglePostProcessor(redis, {
88
+ streamName: 'stream:single-service',
89
+ groupName: 'group:single-e2e',
90
+ consumerName: 'consumer:single-e2e-1',
91
+ claimIntervalMs: 100,
92
+ claimMinIdleTimeMs: 50,
93
+ blockMs: 50,
94
+ retry: {
95
+ maxRetries: 1,
96
+ initialDelayMs: 50,
97
+ maxDelayMs: 100,
98
+ backoffMultiplier: 2,
99
+ enableDlq: true,
100
+ },
101
+ });
102
+ const eventId = '00000000-0000-0000-0000-000000000003';
103
+ await pushDbEvent(repository, redis, testLogger, eventId, 'event.changed', [
104
+ 'single-service',
105
+ ]);
106
+ processor.processError = new Error('Persistent failure');
107
+ await processor.start();
108
+ const dlqStreamName = 'stream:single-service-dlq';
109
+ await waitFor(async () => {
110
+ const xrange = await redis.xrange(dlqStreamName, '-', '+');
111
+ return xrange.length === 1;
112
+ }, 3000);
113
+ expect(processor.processedEvents.length).toBe(0);
114
+ const xrange = await redis.xrange(dlqStreamName, '-', '+');
115
+ const dlqFields = xrange[0][1];
116
+ const dlqObj = {};
117
+ for (let i = 0; i < dlqFields.length; i += 2) {
118
+ dlqObj[dlqFields[i]] = dlqFields[i + 1];
119
+ }
120
+ expect(dlqObj.error).toContain('Persistent failure');
121
+ expect(dlqObj.messageId).toBeDefined();
122
+ });
123
+ it('should skip processing and acknowledge when idempotency lock is already acquired', async () => {
124
+ processor = new E2ESinglePostProcessor(redis, {
125
+ streamName: 'stream:single-service',
126
+ groupName: 'group:single-e2e',
127
+ consumerName: 'consumer:single-e2e-1',
128
+ claimIntervalMs: 100,
129
+ claimMinIdleTimeMs: 100,
130
+ blockMs: 50,
131
+ idempotencyTtlSeconds: 10,
132
+ });
133
+ const eventId = '00000000-0000-0000-0000-000000000004';
134
+ await pushDbEvent(repository, redis, testLogger, eventId, 'event.changed', [
135
+ 'single-service',
136
+ ]);
137
+ const streamName = 'stream:single-service';
138
+ const entries = await redis.xrange(streamName, '-', '+');
139
+ expect(entries.length).toBe(1);
140
+ const messageId = entries[0][0];
141
+ const lockKey = `idempotency:post-processor:group:single-e2e:${messageId}`;
142
+ await redis.set(lockKey, 'processed', 'EX', 10);
143
+ await processor.start();
144
+ await new Promise((resolve) => setTimeout(resolve, 300));
145
+ expect(processor.processedEvents.length).toBe(0);
146
+ const pending = await redis.xpending(streamName, 'group:single-e2e', '-', '+', 10);
147
+ expect(pending.length).toBe(0);
148
+ });
149
+ it('should recover and process subsequent messages when processEvent throws an error', async () => {
150
+ processor = new E2ESinglePostProcessor(redis, {
151
+ streamName: 'stream:single-service',
152
+ groupName: 'group:single-e2e',
153
+ consumerName: 'consumer:single-e2e-1',
154
+ claimIntervalMs: 100,
155
+ claimMinIdleTimeMs: 100,
156
+ blockMs: 50,
157
+ retry: {
158
+ maxRetries: 0,
159
+ initialDelayMs: 50,
160
+ maxDelayMs: 100,
161
+ backoffMultiplier: 1.5,
162
+ enableDlq: true,
163
+ },
164
+ });
165
+ const eventIdFail = '00000000-0000-0000-0000-000000000005';
166
+ const eventIdOk = '00000000-0000-0000-0000-000000000006';
167
+ await pushDbEvent(repository, redis, testLogger, eventIdFail, 'event.changed', [
168
+ 'single-service',
169
+ ]);
170
+ await pushDbEvent(repository, redis, testLogger, eventIdOk, 'event.changed', [
171
+ 'single-service',
172
+ ]);
173
+ processor.processError = new Error('Failure on first message');
174
+ processor.failEventIds.add(eventIdFail);
175
+ await processor.start();
176
+ const dlqStreamName = 'stream:single-service-dlq';
177
+ await waitFor(async () => {
178
+ const xrange = await redis.xrange(dlqStreamName, '-', '+');
179
+ return xrange.length === 1;
180
+ }, 3000);
181
+ await waitFor(() => processor.processedEvents.length === 1, 3000);
182
+ expect(processor.processedEvents[0].event.id).toBe(eventIdOk);
183
+ });
184
+ it('should transition circuit breaker to OPEN on consecutive failures and HALF_OPEN after reset timeout', async () => {
185
+ processor = new E2ESinglePostProcessor(redis, {
186
+ streamName: 'stream:single-service',
187
+ groupName: 'group:single-e2e',
188
+ consumerName: 'consumer:single-e2e-1',
189
+ claimIntervalMs: 100,
190
+ claimMinIdleTimeMs: 100,
191
+ blockMs: 50,
192
+ circuitBreaker: {
193
+ failureThreshold: 2,
194
+ resetTimeoutMs: 1000,
195
+ successThreshold: 1,
196
+ },
197
+ retry: {
198
+ maxRetries: 0,
199
+ initialDelayMs: 50,
200
+ maxDelayMs: 100,
201
+ backoffMultiplier: 1.5,
202
+ enableDlq: true,
203
+ },
204
+ });
205
+ const eventId1 = '00000000-0000-0000-0000-000000000007';
206
+ const eventId2 = '00000000-0000-0000-0000-000000000008';
207
+ await pushDbEvent(repository, redis, testLogger, eventId1, 'event.changed', [
208
+ 'single-service',
209
+ ]);
210
+ await pushDbEvent(repository, redis, testLogger, eventId2, 'event.changed', [
211
+ 'single-service',
212
+ ]);
213
+ processor.processError = new Error('CB failure trigger');
214
+ processor.failEventIds.add(eventId1);
215
+ processor.failEventIds.add(eventId2);
216
+ await processor.start();
217
+ const cb = processor.getCircuitBreaker();
218
+ await waitFor(() => cb.getState() === CircuitBreakerState.OPEN, 3000);
219
+ const eventId3 = '00000000-0000-0000-0000-000000000009';
220
+ await pushDbEvent(repository, redis, testLogger, eventId3, 'event.changed', [
221
+ 'single-service',
222
+ ]);
223
+ await new Promise((resolve) => setTimeout(resolve, 100));
224
+ expect(cb.getState()).toBe(CircuitBreakerState.OPEN);
225
+ expect(processor.processedEvents.length).toBe(0);
226
+ await waitFor(() => processor.processedEvents.length === 1, 4000);
227
+ expect(processor.processedEvents[0].event.id).toBe(eventId3);
228
+ expect(cb.getState()).toBe(CircuitBreakerState.CLOSED);
229
+ });
230
+ it('should leave messages untouched in a stream that nobody processes', async () => {
231
+ processor = new E2ESinglePostProcessor(redis, {
232
+ streamName: 'stream:single-service',
233
+ groupName: 'group:single-e2e',
234
+ consumerName: 'consumer:single-e2e-1',
235
+ claimIntervalMs: 100,
236
+ claimMinIdleTimeMs: 100,
237
+ blockMs: 50,
238
+ });
239
+ const eventId = '00000000-0000-0000-0000-000000000010';
240
+ await pushDbEvent(repository, redis, testLogger, eventId, 'event.changed', [
241
+ 'other-service',
242
+ ]);
243
+ await processor.start();
244
+ await new Promise((resolve) => setTimeout(resolve, 200));
245
+ expect(processor.processedEvents.length).toBe(0);
246
+ const len = await redis.xlen('stream:other-service');
247
+ expect(len).toBe(1);
248
+ });
249
+ it('should load balance and distribute messages across multiple concurrent processors in the same group', async () => {
250
+ const processor2 = new E2ESinglePostProcessor(redis, {
251
+ streamName: 'stream:single-service',
252
+ groupName: 'group:single-e2e-concurrent',
253
+ consumerName: 'consumer:single-e2e-2',
254
+ claimIntervalMs: 100,
255
+ claimMinIdleTimeMs: 100,
256
+ blockMs: 50,
257
+ });
258
+ processor = new E2ESinglePostProcessor(redis, {
259
+ streamName: 'stream:single-service',
260
+ groupName: 'group:single-e2e-concurrent',
261
+ consumerName: 'consumer:single-e2e-1',
262
+ claimIntervalMs: 100,
263
+ claimMinIdleTimeMs: 100,
264
+ blockMs: 50,
265
+ });
266
+ for (let i = 1; i <= 10; i++) {
267
+ const eventId = `00000000-0000-0000-0000-0000000000${(10 + i).toString()}`;
268
+ await pushDbEvent(repository, redis, testLogger, eventId, 'event.changed', [
269
+ 'single-service',
270
+ ]);
271
+ }
272
+ await processor.start();
273
+ await processor2.start();
274
+ await waitFor(() => {
275
+ const totalProcessed = processor.processedEvents.length + processor2.processedEvents.length;
276
+ return totalProcessed === 10;
277
+ }, 5000);
278
+ expect(processor.processedEvents.length).toBeGreaterThan(0);
279
+ expect(processor2.processedEvents.length).toBeGreaterThan(0);
280
+ const ids = [
281
+ ...processor.processedEvents.map((e) => e.event.id),
282
+ ...processor2.processedEvents.map((e) => e.event.id),
283
+ ];
284
+ expect(new Set(ids).size).toBe(10);
285
+ await processor2.stop();
286
+ });
287
+ });
288
+ //# sourceMappingURL=single-post-processor-e2e.int.spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"single-post-processor-e2e.int.spec.js","sourceRoot":"","sources":["../../../../src/test/specs/integration/single-post-processor-e2e.int.spec.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ import { BatchPostProcessor } from '../../../core/processors/batch.post-processor.js';
2
+ import type { BatchEventItem } from '../../../interfaces/index.js';
3
+ import { EventMessagingType } from '@volontariapp/messaging';
4
+ export declare class E2EBatchPostProcessor extends BatchPostProcessor<typeof EventMessagingType.EVENT_CHANGED> {
5
+ processedBatches: BatchEventItem<typeof EventMessagingType.EVENT_CHANGED>[][];
6
+ processError: Error | null;
7
+ failEventIds: Set<string>;
8
+ processDelayMs: number;
9
+ getCircuitBreaker(): import("../../../index.js").CircuitBreaker;
10
+ protected processEvents(events: BatchEventItem<typeof EventMessagingType.EVENT_CHANGED>[]): Promise<void>;
11
+ shouldProcess(eventType: string): boolean;
12
+ acknowledge(messageId: string): Promise<void>;
13
+ }
14
+ //# sourceMappingURL=e2e-batch-post-processor.class.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"e2e-batch-post-processor.class.d.ts","sourceRoot":"","sources":["../../../../src/test/utils/classes/e2e-batch-post-processor.class.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,kDAAkD,CAAC;AACtF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AACnE,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAE7D,qBAAa,qBAAsB,SAAQ,kBAAkB,CAC3D,OAAO,kBAAkB,CAAC,aAAa,CACxC;IACQ,gBAAgB,EAAE,cAAc,CAAC,OAAO,kBAAkB,CAAC,aAAa,CAAC,EAAE,EAAE,CAAM;IACnF,YAAY,EAAE,KAAK,GAAG,IAAI,CAAQ;IAClC,YAAY,EAAE,GAAG,CAAC,MAAM,CAAC,CAAa;IACtC,cAAc,SAAK;IAEnB,iBAAiB;cAIC,aAAa,CACpC,MAAM,EAAE,cAAc,CAAC,OAAO,kBAAkB,CAAC,aAAa,CAAC,EAAE,GAChE,OAAO,CAAC,IAAI,CAAC;IAiBA,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO;IAInC,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAGpE"}
@@ -0,0 +1,34 @@
1
+ import { BatchPostProcessor } from '../../../core/processors/batch.post-processor.js';
2
+ import { EventMessagingType } from '@volontariapp/messaging';
3
+ export class E2EBatchPostProcessor extends BatchPostProcessor {
4
+ processedBatches = [];
5
+ processError = null;
6
+ failEventIds = new Set();
7
+ processDelayMs = 0;
8
+ getCircuitBreaker() {
9
+ return this.circuitBreaker;
10
+ }
11
+ async processEvents(events) {
12
+ if (this.processDelayMs > 0) {
13
+ await new Promise((resolve) => setTimeout(resolve, this.processDelayMs));
14
+ }
15
+ if (this.processError) {
16
+ if (this.failEventIds.size === 0) {
17
+ throw this.processError;
18
+ }
19
+ for (const item of events) {
20
+ if (this.failEventIds.has(item.event.id)) {
21
+ throw this.processError;
22
+ }
23
+ }
24
+ }
25
+ this.processedBatches.push(events);
26
+ }
27
+ shouldProcess(eventType) {
28
+ return eventType === EventMessagingType.EVENT_CHANGED;
29
+ }
30
+ async acknowledge(messageId) {
31
+ return super.acknowledge(messageId);
32
+ }
33
+ }
34
+ //# sourceMappingURL=e2e-batch-post-processor.class.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"e2e-batch-post-processor.class.js","sourceRoot":"","sources":["../../../../src/test/utils/classes/e2e-batch-post-processor.class.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,kDAAkD,CAAC;AAEtF,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAE7D,MAAM,OAAO,qBAAsB,SAAQ,kBAE1C;IACQ,gBAAgB,GAAgE,EAAE,CAAC;IACnF,YAAY,GAAiB,IAAI,CAAC;IAClC,YAAY,GAAgB,IAAI,GAAG,EAAE,CAAC;IACtC,cAAc,GAAG,CAAC,CAAC;IAEnB,iBAAiB;QACtB,OAAO,IAAI,CAAC,cAAc,CAAC;IAC7B,CAAC;IAEkB,KAAK,CAAC,aAAa,CACpC,MAAiE;QAEjE,IAAI,IAAI,CAAC,cAAc,GAAG,CAAC,EAAE,CAAC;YAC5B,MAAM,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC;QAC3E,CAAC;QACD,IAAI,IAAI,CAAC,YAAY,EAAE,CAAC;YACtB,IAAI,IAAI,CAAC,YAAY,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;gBACjC,MAAM,IAAI,CAAC,YAAY,CAAC;YAC1B,CAAC;YACD,KAAK,MAAM,IAAI,IAAI,MAAM,EAAE,CAAC;gBAC1B,IAAI,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,CAAC;oBACzC,MAAM,IAAI,CAAC,YAAY,CAAC;gBAC1B,CAAC;YACH,CAAC;QACH,CAAC;QACD,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACrC,CAAC;IAEe,aAAa,CAAC,SAAiB;QAC7C,OAAO,SAAS,KAAM,kBAAkB,CAAC,aAAwB,CAAC;IACpE,CAAC;IAEe,KAAK,CAAC,WAAW,CAAC,SAAiB;QACjD,OAAO,KAAK,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC;IACtC,CAAC;CACF"}