@volontariapp/outbox 0.3.1 → 0.4.0-snap-2c644e5

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 (46) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/dist/consumers/event-queue.consumer.d.ts +2 -2
  3. package/dist/consumers/event-queue.consumer.d.ts.map +1 -1
  4. package/dist/consumers/event-queue.consumer.js +2 -2
  5. package/dist/consumers/event-queue.consumer.js.map +1 -1
  6. package/dist/consumers/jobs-outbox.consumer.d.ts +2 -2
  7. package/dist/consumers/jobs-outbox.consumer.d.ts.map +1 -1
  8. package/dist/consumers/jobs-outbox.consumer.js +2 -2
  9. package/dist/consumers/jobs-outbox.consumer.js.map +1 -1
  10. package/dist/index.d.ts +2 -0
  11. package/dist/index.d.ts.map +1 -1
  12. package/dist/index.js +2 -0
  13. package/dist/index.js.map +1 -1
  14. package/dist/pushers/event-queue.pusher.d.ts +9 -0
  15. package/dist/pushers/event-queue.pusher.d.ts.map +1 -0
  16. package/dist/pushers/event-queue.pusher.js +17 -0
  17. package/dist/pushers/event-queue.pusher.js.map +1 -0
  18. package/dist/pushers/jobs-outbox.pusher.d.ts +14 -0
  19. package/dist/pushers/jobs-outbox.pusher.d.ts.map +1 -0
  20. package/dist/pushers/jobs-outbox.pusher.js +107 -0
  21. package/dist/pushers/jobs-outbox.pusher.js.map +1 -0
  22. package/dist/test/consumers/event/event-queue.consumer.int.spec.js +34 -7
  23. package/dist/test/consumers/event/event-queue.consumer.int.spec.js.map +1 -1
  24. package/dist/test/consumers/event/event-queue.consumer.unit.spec.js +14 -8
  25. package/dist/test/consumers/event/event-queue.consumer.unit.spec.js.map +1 -1
  26. package/dist/test/consumers/jobs/jobs-outbox.consumer.int.spec.js +36 -5
  27. package/dist/test/consumers/jobs/jobs-outbox.consumer.int.spec.js.map +1 -1
  28. package/dist/test/consumers/jobs/jobs-outbox.consumer.unit.spec.js +15 -8
  29. package/dist/test/consumers/jobs/jobs-outbox.consumer.unit.spec.js.map +1 -1
  30. package/dist/test/data-source.js +1 -1
  31. package/dist/test/global-setup.d.ts.map +1 -1
  32. package/dist/test/global-setup.js +18 -2
  33. package/dist/test/global-setup.js.map +1 -1
  34. package/dist/test/pushers/jobs-outbox.pusher.int.spec.d.ts +2 -0
  35. package/dist/test/pushers/jobs-outbox.pusher.int.spec.d.ts.map +1 -0
  36. package/dist/test/pushers/jobs-outbox.pusher.int.spec.js +104 -0
  37. package/dist/test/pushers/jobs-outbox.pusher.int.spec.js.map +1 -0
  38. package/dist/test/pushers/jobs-outbox.pusher.unit.spec.d.ts +2 -0
  39. package/dist/test/pushers/jobs-outbox.pusher.unit.spec.d.ts.map +1 -0
  40. package/dist/test/pushers/jobs-outbox.pusher.unit.spec.js +102 -0
  41. package/dist/test/pushers/jobs-outbox.pusher.unit.spec.js.map +1 -0
  42. package/dist/test/redis-config.d.ts +8 -0
  43. package/dist/test/redis-config.d.ts.map +1 -0
  44. package/dist/test/redis-config.js +26 -0
  45. package/dist/test/redis-config.js.map +1 -0
  46. package/package.json +6 -3
package/CHANGELOG.md CHANGED
@@ -1,5 +1,16 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.4.0
4
+
5
+ ### Minor Changes
6
+
7
+ - Added outboxPusher, jobsOutboxPusher and updated outboxConsumer implementation & behavior
8
+
9
+ ### Patch Changes
10
+
11
+ - Updated dependencies []:
12
+ - @volontariapp/database@1.13.0
13
+
3
14
  ## 0.3.1
4
15
 
5
16
  ### Patch Changes
@@ -1,7 +1,7 @@
1
- import type { BaseRepository, EventQueueEntity, EventQueueModel, EventType } from '@volontariapp/database';
1
+ import type { BaseRepository, EventQueueEntity, EventQueueModel, EventType, OutboxPusher } from '@volontariapp/database';
2
2
  import { OutboxConsumer } from '@volontariapp/database';
3
3
  import type { Logger } from '@volontariapp/logger';
4
4
  export declare class EventQueueConsumer<K extends EventType = EventType> extends OutboxConsumer<EventQueueModel, EventQueueEntity<K>> {
5
- constructor(logger: Logger, repository: BaseRepository<EventQueueModel, EventQueueEntity<K>, string>, batchSize: number);
5
+ constructor(logger: Logger, repository: BaseRepository<EventQueueModel, EventQueueEntity<K>, string>, batchSize: number, pusher: OutboxPusher<EventQueueEntity<K>>);
6
6
  }
7
7
  //# sourceMappingURL=event-queue.consumer.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"event-queue.consumer.d.ts","sourceRoot":"","sources":["../../src/consumers/event-queue.consumer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,cAAc,EACd,gBAAgB,EAChB,eAAe,EACf,SAAS,EACV,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAGnD,qBAAa,kBAAkB,CAAC,CAAC,SAAS,SAAS,GAAG,SAAS,CAAE,SAAQ,cAAc,CACrF,eAAe,EACf,gBAAgB,CAAC,CAAC,CAAC,CACpB;gBAEG,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,cAAc,CAAC,eAAe,EAAE,gBAAgB,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,EACxE,SAAS,EAAE,MAAM;CAIpB"}
1
+ {"version":3,"file":"event-queue.consumer.d.ts","sourceRoot":"","sources":["../../src/consumers/event-queue.consumer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,cAAc,EACd,gBAAgB,EAChB,eAAe,EACf,SAAS,EACT,YAAY,EACb,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAGnD,qBAAa,kBAAkB,CAAC,CAAC,SAAS,SAAS,GAAG,SAAS,CAAE,SAAQ,cAAc,CACrF,eAAe,EACf,gBAAgB,CAAC,CAAC,CAAC,CACpB;gBAEG,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,cAAc,CAAC,eAAe,EAAE,gBAAgB,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,EACxE,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,YAAY,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC;CAI5C"}
@@ -1,8 +1,8 @@
1
1
  import { OutboxConsumer } from '@volontariapp/database';
2
2
  import { EventQueueDispatcher } from '../dispatchers/event-queue.dispatcher.js';
3
3
  export class EventQueueConsumer extends OutboxConsumer {
4
- constructor(logger, repository, batchSize) {
5
- super(logger, repository, batchSize, new EventQueueDispatcher(logger, repository));
4
+ constructor(logger, repository, batchSize, pusher) {
5
+ super(logger, repository, batchSize, new EventQueueDispatcher(logger, repository), pusher);
6
6
  }
7
7
  }
8
8
  //# sourceMappingURL=event-queue.consumer.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"event-queue.consumer.js","sourceRoot":"","sources":["../../src/consumers/event-queue.consumer.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAExD,OAAO,EAAE,oBAAoB,EAAE,MAAM,0CAA0C,CAAC;AAEhF,MAAM,OAAO,kBAAoD,SAAQ,cAGxE;IACC,YACE,MAAc,EACd,UAAwE,EACxE,SAAiB;QAEjB,KAAK,CAAC,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,IAAI,oBAAoB,CAAI,MAAM,EAAE,UAAU,CAAC,CAAC,CAAC;IACxF,CAAC;CACF"}
1
+ {"version":3,"file":"event-queue.consumer.js","sourceRoot":"","sources":["../../src/consumers/event-queue.consumer.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAExD,OAAO,EAAE,oBAAoB,EAAE,MAAM,0CAA0C,CAAC;AAEhF,MAAM,OAAO,kBAAoD,SAAQ,cAGxE;IACC,YACE,MAAc,EACd,UAAwE,EACxE,SAAiB,EACjB,MAAyC;QAEzC,KAAK,CAAC,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,IAAI,oBAAoB,CAAI,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,CAAC,CAAC;IAChG,CAAC;CACF"}
@@ -1,8 +1,8 @@
1
1
  import { OutboxConsumer } from '@volontariapp/database';
2
- import type { JobsOutboxEntity, JobsOutboxModel, JobType } from '@volontariapp/database';
2
+ import type { JobsOutboxEntity, JobsOutboxModel, JobType, OutboxPusher } from '@volontariapp/database';
3
3
  import type { Logger } from '@volontariapp/logger';
4
4
  import type { BaseRepository } from '@volontariapp/database';
5
5
  export declare class JobsOutboxConsumer<K extends JobType = JobType> extends OutboxConsumer<JobsOutboxModel, JobsOutboxEntity<K>> {
6
- constructor(logger: Logger, repository: BaseRepository<JobsOutboxModel, JobsOutboxEntity<K>, string>, batchSize: number);
6
+ constructor(logger: Logger, repository: BaseRepository<JobsOutboxModel, JobsOutboxEntity<K>, string>, batchSize: number, pusher: OutboxPusher<JobsOutboxEntity<K>>);
7
7
  }
8
8
  //# sourceMappingURL=jobs-outbox.consumer.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"jobs-outbox.consumer.d.ts","sourceRoot":"","sources":["../../src/consumers/jobs-outbox.consumer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AACzF,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAEnD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAE7D,qBAAa,kBAAkB,CAAC,CAAC,SAAS,OAAO,GAAG,OAAO,CAAE,SAAQ,cAAc,CACjF,eAAe,EACf,gBAAgB,CAAC,CAAC,CAAC,CACpB;gBAEG,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,cAAc,CAAC,eAAe,EAAE,gBAAgB,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,EACxE,SAAS,EAAE,MAAM;CAIpB"}
1
+ {"version":3,"file":"jobs-outbox.consumer.d.ts","sourceRoot":"","sources":["../../src/consumers/jobs-outbox.consumer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,KAAK,EACV,gBAAgB,EAChB,eAAe,EACf,OAAO,EACP,YAAY,EACb,MAAM,wBAAwB,CAAC;AAChC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAEnD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAE7D,qBAAa,kBAAkB,CAAC,CAAC,SAAS,OAAO,GAAG,OAAO,CAAE,SAAQ,cAAc,CACjF,eAAe,EACf,gBAAgB,CAAC,CAAC,CAAC,CACpB;gBAEG,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,cAAc,CAAC,eAAe,EAAE,gBAAgB,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,EACxE,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,YAAY,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC;CAI5C"}
@@ -1,8 +1,8 @@
1
1
  import { OutboxConsumer } from '@volontariapp/database';
2
2
  import { JobsOutboxDispatcher } from '../dispatchers/jobs-outbox.dispatcher.js';
3
3
  export class JobsOutboxConsumer extends OutboxConsumer {
4
- constructor(logger, repository, batchSize) {
5
- super(logger, repository, batchSize, new JobsOutboxDispatcher(logger, repository));
4
+ constructor(logger, repository, batchSize, pusher) {
5
+ super(logger, repository, batchSize, new JobsOutboxDispatcher(logger, repository), pusher);
6
6
  }
7
7
  }
8
8
  //# sourceMappingURL=jobs-outbox.consumer.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"jobs-outbox.consumer.js","sourceRoot":"","sources":["../../src/consumers/jobs-outbox.consumer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAGxD,OAAO,EAAE,oBAAoB,EAAE,MAAM,0CAA0C,CAAC;AAGhF,MAAM,OAAO,kBAAgD,SAAQ,cAGpE;IACC,YACE,MAAc,EACd,UAAwE,EACxE,SAAiB;QAEjB,KAAK,CAAC,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,IAAI,oBAAoB,CAAI,MAAM,EAAE,UAAU,CAAC,CAAC,CAAC;IACxF,CAAC;CACF"}
1
+ {"version":3,"file":"jobs-outbox.consumer.js","sourceRoot":"","sources":["../../src/consumers/jobs-outbox.consumer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAQxD,OAAO,EAAE,oBAAoB,EAAE,MAAM,0CAA0C,CAAC;AAGhF,MAAM,OAAO,kBAAgD,SAAQ,cAGpE;IACC,YACE,MAAc,EACd,UAAwE,EACxE,SAAiB,EACjB,MAAyC;QAEzC,KAAK,CAAC,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,IAAI,oBAAoB,CAAI,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,CAAC,CAAC;IAChG,CAAC;CACF"}
package/dist/index.d.ts CHANGED
@@ -4,4 +4,6 @@ export * from './consumers/event-queue.consumer.js';
4
4
  export * from './consumers/jobs-outbox.consumer.js';
5
5
  export * from './dispatchers/event-queue.dispatcher.js';
6
6
  export * from './dispatchers/jobs-outbox.dispatcher.js';
7
+ export * from './pushers/event-queue.pusher.js';
8
+ export * from './pushers/jobs-outbox.pusher.js';
7
9
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,iCAAiC,CAAC;AAChD,cAAc,iCAAiC,CAAC;AAEhD,cAAc,qCAAqC,CAAC;AACpD,cAAc,qCAAqC,CAAC;AAEpD,cAAc,yCAAyC,CAAC;AACxD,cAAc,yCAAyC,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,iCAAiC,CAAC;AAChD,cAAc,iCAAiC,CAAC;AAEhD,cAAc,qCAAqC,CAAC;AACpD,cAAc,qCAAqC,CAAC;AAEpD,cAAc,yCAAyC,CAAC;AACxD,cAAc,yCAAyC,CAAC;AAExD,cAAc,iCAAiC,CAAC;AAChD,cAAc,iCAAiC,CAAC"}
package/dist/index.js CHANGED
@@ -4,4 +4,6 @@ export * from './consumers/event-queue.consumer.js';
4
4
  export * from './consumers/jobs-outbox.consumer.js';
5
5
  export * from './dispatchers/event-queue.dispatcher.js';
6
6
  export * from './dispatchers/jobs-outbox.dispatcher.js';
7
+ export * from './pushers/event-queue.pusher.js';
8
+ export * from './pushers/jobs-outbox.pusher.js';
7
9
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,iCAAiC,CAAC;AAChD,cAAc,iCAAiC,CAAC;AAEhD,cAAc,qCAAqC,CAAC;AACpD,cAAc,qCAAqC,CAAC;AAEpD,cAAc,yCAAyC,CAAC;AACxD,cAAc,yCAAyC,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,iCAAiC,CAAC;AAChD,cAAc,iCAAiC,CAAC;AAEhD,cAAc,qCAAqC,CAAC;AACpD,cAAc,qCAAqC,CAAC;AAEpD,cAAc,yCAAyC,CAAC;AACxD,cAAc,yCAAyC,CAAC;AAExD,cAAc,iCAAiC,CAAC;AAChD,cAAc,iCAAiC,CAAC"}
@@ -0,0 +1,9 @@
1
+ import { OutboxPusher, type EventQueueEntity } from '@volontariapp/database';
2
+ import type { Logger } from '@volontariapp/logger';
3
+ export declare class EventQueuePusher extends OutboxPusher<EventQueueEntity> {
4
+ private readonly logger;
5
+ constructor(logger: Logger);
6
+ pushElement(entity: EventQueueEntity): Promise<void>;
7
+ pushBulkElement(entities: EventQueueEntity[]): Promise<void>;
8
+ }
9
+ //# sourceMappingURL=event-queue.pusher.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"event-queue.pusher.d.ts","sourceRoot":"","sources":["../../src/pushers/event-queue.pusher.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,KAAK,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC7E,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAEnD,qBAAa,gBAAiB,SAAQ,YAAY,CAAC,gBAAgB,CAAC;IACtD,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAN,MAAM,EAAE,MAAM;IAI3C,WAAW,CAAC,MAAM,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;IAMpD,eAAe,CAAC,QAAQ,EAAE,gBAAgB,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;CAK7D"}
@@ -0,0 +1,17 @@
1
+ import { OutboxPusher } from '@volontariapp/database';
2
+ export class EventQueuePusher extends OutboxPusher {
3
+ logger;
4
+ constructor(logger) {
5
+ super();
6
+ this.logger = logger;
7
+ }
8
+ pushElement(entity) {
9
+ this.logger.info(`Pushing event queue item ${entity.id.toString()}`);
10
+ return Promise.resolve();
11
+ }
12
+ pushBulkElement(entities) {
13
+ this.logger.info(`Pushing ${entities.length.toString()} event queue items`);
14
+ return Promise.resolve();
15
+ }
16
+ }
17
+ //# sourceMappingURL=event-queue.pusher.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"event-queue.pusher.js","sourceRoot":"","sources":["../../src/pushers/event-queue.pusher.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAyB,MAAM,wBAAwB,CAAC;AAG7E,MAAM,OAAO,gBAAiB,SAAQ,YAA8B;IACrC;IAA7B,YAA6B,MAAc;QACzC,KAAK,EAAE,CAAC;QADmB,WAAM,GAAN,MAAM,CAAQ;IAE3C,CAAC;IAED,WAAW,CAAC,MAAwB;QAClC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,4BAA4B,MAAM,CAAC,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;QAErE,OAAO,OAAO,CAAC,OAAO,EAAE,CAAC;IAC3B,CAAC;IAED,eAAe,CAAC,QAA4B;QAC1C,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,WAAW,QAAQ,CAAC,MAAM,CAAC,QAAQ,EAAE,oBAAoB,CAAC,CAAC;QAE5E,OAAO,OAAO,CAAC,OAAO,EAAE,CAAC;IAC3B,CAAC;CACF"}
@@ -0,0 +1,14 @@
1
+ import { OutboxPusher, type JobsOutboxEntity } from '@volontariapp/database';
2
+ import type { Logger } from '@volontariapp/logger';
3
+ import type { RedisConfig } from '@volontariapp/config';
4
+ export declare class JobsOutboxPusher extends OutboxPusher<JobsOutboxEntity> {
5
+ private readonly logger;
6
+ private readonly queues;
7
+ private readonly redisOptions;
8
+ constructor(logger: Logger, redisConfig: RedisConfig);
9
+ private getQueue;
10
+ pushElement(entity: JobsOutboxEntity): Promise<void>;
11
+ pushBulkElement(entities: JobsOutboxEntity[]): Promise<void>;
12
+ close(): Promise<void>;
13
+ }
14
+ //# sourceMappingURL=jobs-outbox.pusher.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jobs-outbox.pusher.d.ts","sourceRoot":"","sources":["../../src/pushers/jobs-outbox.pusher.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,KAAK,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC7E,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAEnD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAExD,qBAAa,gBAAiB,SAAQ,YAAY,CAAC,gBAAgB,CAAC;IAKhE,OAAO,CAAC,QAAQ,CAAC,MAAM;IAJzB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA4B;IACnD,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAe;gBAGzB,MAAM,EAAE,MAAM,EAC/B,WAAW,EAAE,WAAW;IAc1B,OAAO,CAAC,QAAQ;IAoBV,WAAW,CAAC,MAAM,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;IAwBpD,eAAe,CAAC,QAAQ,EAAE,gBAAgB,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IA0C5D,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAY7B"}
@@ -0,0 +1,107 @@
1
+ import { Queue } from 'bullmq';
2
+ import { OutboxPusher } from '@volontariapp/database';
3
+ export class JobsOutboxPusher extends OutboxPusher {
4
+ logger;
5
+ queues = new Map();
6
+ redisOptions;
7
+ constructor(logger, redisConfig) {
8
+ super();
9
+ this.logger = logger;
10
+ this.redisOptions = {
11
+ host: redisConfig.host,
12
+ port: redisConfig.port,
13
+ password: redisConfig.password,
14
+ db: redisConfig.dbIndex,
15
+ keyPrefix: redisConfig.keyPrefix,
16
+ maxRetriesPerRequest: null,
17
+ };
18
+ }
19
+ getQueue(targetService) {
20
+ let queue = this.queues.get(targetService);
21
+ if (!queue) {
22
+ this.logger.debug(`Creating new BullMQ queue for service: ${targetService}`);
23
+ queue = new Queue(targetService, {
24
+ connection: this.redisOptions,
25
+ defaultJobOptions: {
26
+ attempts: 3,
27
+ backoff: {
28
+ type: 'exponential',
29
+ delay: 1000,
30
+ },
31
+ removeOnComplete: true,
32
+ },
33
+ });
34
+ this.queues.set(targetService, queue);
35
+ }
36
+ return queue;
37
+ }
38
+ async pushElement(entity) {
39
+ this.logger.info(`Pushing job outbox item ${entity.id.toString()} to target: ${entity.target}`);
40
+ try {
41
+ const queue = this.getQueue(entity.target);
42
+ const jobOptions = {
43
+ jobId: `outbox-${entity.id.toString()}`,
44
+ };
45
+ if (entity.scheduledAt) {
46
+ const delay = entity.scheduledAt.getTime() - Date.now();
47
+ if (delay > 0) {
48
+ jobOptions.delay = delay;
49
+ }
50
+ }
51
+ await queue.add(entity.type, entity.payload, jobOptions);
52
+ }
53
+ catch (error) {
54
+ this.logger.error(`Failed to push job outbox item ${entity.id.toString()}`, { error });
55
+ throw error;
56
+ }
57
+ }
58
+ async pushBulkElement(entities) {
59
+ this.logger.info(`Pushing ${entities.length.toString()} job outbox items`);
60
+ const targets = new Map();
61
+ for (const entity of entities) {
62
+ const targetEntities = targets.get(entity.target) ?? [];
63
+ targetEntities.push(entity);
64
+ targets.set(entity.target, targetEntities);
65
+ }
66
+ try {
67
+ await Promise.all(Array.from(targets.entries()).map(async ([target, targetEntities]) => {
68
+ const queue = this.getQueue(target);
69
+ const jobs = targetEntities.map((entity) => {
70
+ const jobOptions = {
71
+ jobId: `outbox-${entity.id.toString()}`,
72
+ };
73
+ if (entity.scheduledAt) {
74
+ const delay = entity.scheduledAt.getTime() - Date.now();
75
+ if (delay > 0) {
76
+ jobOptions.delay = delay;
77
+ }
78
+ }
79
+ return {
80
+ name: entity.type,
81
+ data: entity.payload,
82
+ opts: jobOptions,
83
+ };
84
+ });
85
+ await queue.addBulk(jobs);
86
+ }));
87
+ }
88
+ catch (error) {
89
+ this.logger.error(`Failed to push bulk job outbox items`, { error });
90
+ throw error;
91
+ }
92
+ }
93
+ async close() {
94
+ this.logger.info('Closing all BullMQ queues');
95
+ const closePromises = Array.from(this.queues.values()).map(async (q) => {
96
+ try {
97
+ await q.close();
98
+ }
99
+ catch (error) {
100
+ this.logger.error(`Error closing queue ${q.name}`, { error });
101
+ }
102
+ });
103
+ await Promise.all(closePromises);
104
+ this.queues.clear();
105
+ }
106
+ }
107
+ //# sourceMappingURL=jobs-outbox.pusher.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jobs-outbox.pusher.js","sourceRoot":"","sources":["../../src/pushers/jobs-outbox.pusher.ts"],"names":[],"mappings":"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"}
@@ -1,27 +1,31 @@
1
- import { describe, expect, it, beforeAll, afterAll, beforeEach } from '@jest/globals';
1
+ import { describe, expect, it, beforeAll, afterAll, beforeEach, jest } from '@jest/globals';
2
2
  import { databaseMapper, EventQueueModel, EventQueueEntity, OutboxStatus, } from '@volontariapp/database';
3
3
  import { testDataSource, initializeTestDb, closeTestDb } from '../../data-source.js';
4
4
  import { EventQueueConsumer } from '../../../consumers/event-queue.consumer.js';
5
5
  import { TestEventQueueRepository } from '../../utils/repositories/event-queue-test.repository.js';
6
6
  import { makeLoggerMock } from '../../utils/helpers/logger-mock.helper.js';
7
+ import { EventQueuePusher } from '../../../pushers/event-queue.pusher.js';
7
8
  describe('EventQueueConsumer (Integration)', () => {
8
9
  let consumer;
9
10
  let repository;
11
+ let pusher;
10
12
  const logger = makeLoggerMock();
11
13
  beforeAll(async () => {
12
14
  await initializeTestDb();
13
15
  databaseMapper.registerBidirectional(EventQueueModel, EventQueueEntity);
14
16
  repository = testDataSource.getRepository(EventQueueModel);
17
+ pusher = new EventQueuePusher(logger);
15
18
  });
16
19
  afterAll(async () => {
17
20
  await closeTestDb();
18
21
  });
19
22
  beforeEach(async () => {
20
23
  await repository.createQueryBuilder().delete().execute();
24
+ jest.clearAllMocks();
21
25
  });
22
26
  it('fetchPendingItems() should fetch pending items and mark them as processing', async () => {
23
27
  const testRepository = new TestEventQueueRepository(repository);
24
- consumer = new EventQueueConsumer(logger, testRepository, 10);
28
+ consumer = new EventQueueConsumer(logger, testRepository, 10, pusher);
25
29
  const eventId = '00000000-0000-0000-0000-000000000001';
26
30
  const pendingItem = repository.create({
27
31
  id: eventId,
@@ -46,13 +50,13 @@ describe('EventQueueConsumer (Integration)', () => {
46
50
  });
47
51
  it('fetchPendingItems() should return empty array when no pending items', async () => {
48
52
  const testRepository = new TestEventQueueRepository(repository);
49
- consumer = new EventQueueConsumer(logger, testRepository, 10);
53
+ consumer = new EventQueueConsumer(logger, testRepository, 10, pusher);
50
54
  const fetchedItems = await consumer.fetchPendingItems();
51
55
  expect(fetchedItems).toHaveLength(0);
52
56
  });
53
57
  it('fetchPendingItems() should respect the size limit', async () => {
54
58
  const testRepository = new TestEventQueueRepository(repository);
55
- consumer = new EventQueueConsumer(logger, testRepository, 2);
59
+ consumer = new EventQueueConsumer(logger, testRepository, 2, pusher);
56
60
  const items = [1, 2, 3].map((i) => repository.create({
57
61
  id: `00000000-0000-0000-0000-00000000000${i.toString()}`,
58
62
  type: 'test.event',
@@ -70,9 +74,9 @@ describe('EventQueueConsumer (Integration)', () => {
70
74
  });
71
75
  it('should handle parallel consumption correctly', async () => {
72
76
  const testRepository = new TestEventQueueRepository(repository);
73
- const consumer1 = new EventQueueConsumer(logger, testRepository, 2);
74
- const consumer2 = new EventQueueConsumer(logger, testRepository, 2);
75
- const consumer3 = new EventQueueConsumer(logger, testRepository, 2);
77
+ const consumer1 = new EventQueueConsumer(logger, testRepository, 2, pusher);
78
+ const consumer2 = new EventQueueConsumer(logger, testRepository, 2, pusher);
79
+ const consumer3 = new EventQueueConsumer(logger, testRepository, 2, pusher);
76
80
  const items = [1, 2, 3, 4].map((i) => repository.create({
77
81
  id: `00000000-0000-0000-0000-00000000000${i.toString()}`,
78
82
  type: 'test.event',
@@ -95,5 +99,28 @@ describe('EventQueueConsumer (Integration)', () => {
95
99
  const lengths = [res1.length, res2.length, res3.length].sort();
96
100
  expect(lengths).toEqual([0, 2, 2]);
97
101
  });
102
+ it('processItems() should push items and mark them as COMPLETED', async () => {
103
+ const testRepository = new TestEventQueueRepository(repository);
104
+ consumer = new EventQueueConsumer(logger, testRepository, 10, pusher);
105
+ const eventId = '00000000-0000-0000-0000-000000000005';
106
+ const item = repository.create({
107
+ id: eventId,
108
+ type: 'test.event',
109
+ emitter: 'test.service',
110
+ status: OutboxStatus.PROCESSING,
111
+ payload: { after: { data: 'test' } },
112
+ createdAt: new Date(),
113
+ updatedAt: new Date(),
114
+ version: 1,
115
+ attempts: 0,
116
+ });
117
+ await repository.save(item);
118
+ const entity = await testRepository.findOneOrFail({ id: eventId });
119
+ const pushSpy = jest.spyOn(pusher, 'pushElement');
120
+ await consumer.processItems([entity]);
121
+ expect(pushSpy).toHaveBeenCalledWith(expect.objectContaining({ id: eventId }));
122
+ const dbItem = await repository.findOneByOrFail({ id: eventId });
123
+ expect(dbItem.status).toBe(OutboxStatus.COMPLETED);
124
+ });
98
125
  });
99
126
  //# sourceMappingURL=event-queue.consumer.int.spec.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"event-queue.consumer.int.spec.js","sourceRoot":"","sources":["../../../../src/test/consumers/event/event-queue.consumer.int.spec.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"event-queue.consumer.int.spec.js","sourceRoot":"","sources":["../../../../src/test/consumers/event/event-queue.consumer.int.spec.ts"],"names":[],"mappings":"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"}
@@ -6,10 +6,15 @@ import { OutboxStatus } from '@volontariapp/database';
6
6
  describe('EventQueueConsumer (Unit)', () => {
7
7
  let consumer;
8
8
  let repository;
9
+ let pusher;
9
10
  const logger = makeLoggerMock();
10
11
  beforeEach(() => {
11
12
  repository = makeEventQueueConsumerRepositoryMock();
12
- consumer = new EventQueueConsumer(logger, repository, 10);
13
+ pusher = {
14
+ pushElement: jest.fn().mockResolvedValue(undefined),
15
+ pushBulkElement: jest.fn().mockResolvedValue(undefined),
16
+ };
17
+ consumer = new EventQueueConsumer(logger, repository, 10, pusher);
13
18
  });
14
19
  afterEach(() => {
15
20
  jest.restoreAllMocks();
@@ -19,9 +24,7 @@ describe('EventQueueConsumer (Unit)', () => {
19
24
  });
20
25
  it('fetchPendingItems() should delegate to repository and return results', async () => {
21
26
  const mockEntities = [{ id: '1' }, { id: '2' }];
22
- const toEntitiesSpy = jest
23
- .spyOn(repository, 'toEntities')
24
- .mockReturnValue(mockEntities);
27
+ const toEntitiesSpy = jest.spyOn(repository, 'toEntities').mockReturnValue(mockEntities);
25
28
  const executeInTransactionSpy = jest.spyOn(repository, 'executeInTransaction');
26
29
  const result = await consumer.fetchPendingItems();
27
30
  expect(executeInTransactionSpy).toHaveBeenCalled();
@@ -29,7 +32,7 @@ describe('EventQueueConsumer (Unit)', () => {
29
32
  expect(result).toEqual(mockEntities);
30
33
  });
31
34
  describe('processItems', () => {
32
- it('should process items and mark them as completed', async () => {
35
+ it('should process items, push them and mark them as completed', async () => {
33
36
  const entities = [
34
37
  { id: '1', status: OutboxStatus.PROCESSING },
35
38
  { id: '2', status: OutboxStatus.PROCESSING },
@@ -38,9 +41,12 @@ describe('EventQueueConsumer (Unit)', () => {
38
41
  .outboxDispatcher;
39
42
  const completedSpy = jest.spyOn(dispatcher, 'markAsCompleted');
40
43
  await consumer.processItems(entities);
44
+ expect(pusher.pushElement).toHaveBeenCalledTimes(2);
45
+ expect(pusher.pushElement).toHaveBeenCalledWith(expect.objectContaining({ id: '1' }));
46
+ expect(pusher.pushElement).toHaveBeenCalledWith(expect.objectContaining({ id: '2' }));
41
47
  expect(completedSpy).toHaveBeenCalledTimes(2);
42
- expect(completedSpy).toHaveBeenCalledWith(entities[0]);
43
- expect(completedSpy).toHaveBeenCalledWith(entities[1]);
48
+ expect(completedSpy).toHaveBeenCalledWith(expect.objectContaining({ id: '1' }));
49
+ expect(completedSpy).toHaveBeenCalledWith(expect.objectContaining({ id: '2' }));
44
50
  });
45
51
  });
46
52
  describe('markItemsAsCompleted', () => {
@@ -54,7 +60,7 @@ describe('EventQueueConsumer (Unit)', () => {
54
60
  const completedSpy = jest.spyOn(dispatcher, 'markAsCompleted');
55
61
  await consumer.markItemsAsCompleted(entities);
56
62
  expect(completedSpy).toHaveBeenCalledTimes(1);
57
- expect(completedSpy).toHaveBeenCalledWith(entities[0]);
63
+ expect(completedSpy).toHaveBeenCalledWith(expect.objectContaining({ id: '1' }));
58
64
  });
59
65
  });
60
66
  });
@@ -1 +1 @@
1
- {"version":3,"file":"event-queue.consumer.unit.spec.js","sourceRoot":"","sources":["../../../../src/test/consumers/event/event-queue.consumer.unit.spec.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"event-queue.consumer.unit.spec.js","sourceRoot":"","sources":["../../../../src/test/consumers/event/event-queue.consumer.unit.spec.ts"],"names":[],"mappings":"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"}
@@ -1,27 +1,33 @@
1
- import { describe, expect, it, beforeAll, afterAll, beforeEach } from '@jest/globals';
1
+ import { describe, expect, it, beforeAll, afterAll, beforeEach, jest } from '@jest/globals';
2
2
  import { databaseMapper, JobsOutboxModel, JobsOutboxEntity, OutboxStatus, } from '@volontariapp/database';
3
3
  import { testDataSource, initializeTestDb, closeTestDb } from '../../data-source.js';
4
4
  import { JobsOutboxConsumer } from '../../../consumers/jobs-outbox.consumer.js';
5
5
  import { TestJobsOutboxRepository } from '../../utils/repositories/jobs-outbox-test.repository.js';
6
6
  import { makeLoggerMock } from '../../utils/helpers/logger-mock.helper.js';
7
+ import { JobsOutboxPusher } from '../../../pushers/jobs-outbox.pusher.js';
8
+ import { testRedisConfig } from '../../redis-config.js';
7
9
  describe('JobsOutboxConsumer (Integration)', () => {
8
10
  let consumer;
9
11
  let repository;
12
+ let pusher;
10
13
  const logger = makeLoggerMock();
11
14
  beforeAll(async () => {
12
15
  await initializeTestDb();
13
16
  databaseMapper.registerBidirectional(JobsOutboxModel, JobsOutboxEntity);
14
17
  repository = testDataSource.getRepository(JobsOutboxModel);
18
+ pusher = new JobsOutboxPusher(logger, testRedisConfig);
15
19
  });
16
20
  afterAll(async () => {
21
+ await pusher.close();
17
22
  await closeTestDb();
18
23
  });
19
24
  beforeEach(async () => {
20
25
  await repository.createQueryBuilder().delete().execute();
26
+ jest.clearAllMocks();
21
27
  });
22
28
  it('fetchPendingItems() should fetch pending items and mark them as processing', async () => {
23
29
  const testRepository = new TestJobsOutboxRepository(repository);
24
- consumer = new JobsOutboxConsumer(logger, testRepository, 10);
30
+ consumer = new JobsOutboxConsumer(logger, testRepository, 10, pusher);
25
31
  const jobId = '00000000-0000-0000-0000-000000000001';
26
32
  const pendingItem = repository.create({
27
33
  id: jobId,
@@ -47,9 +53,9 @@ describe('JobsOutboxConsumer (Integration)', () => {
47
53
  });
48
54
  it('should handle parallel consumption correctly', async () => {
49
55
  const testRepository = new TestJobsOutboxRepository(repository);
50
- const consumer1 = new JobsOutboxConsumer(logger, testRepository, 2);
51
- const consumer2 = new JobsOutboxConsumer(logger, testRepository, 2);
52
- const consumer3 = new JobsOutboxConsumer(logger, testRepository, 2);
56
+ const consumer1 = new JobsOutboxConsumer(logger, testRepository, 2, pusher);
57
+ const consumer2 = new JobsOutboxConsumer(logger, testRepository, 2, pusher);
58
+ const consumer3 = new JobsOutboxConsumer(logger, testRepository, 2, pusher);
53
59
  const items = [1, 2, 3, 4].map((i) => repository.create({
54
60
  id: `00000000-0000-0000-0000-00000000000${i.toString()}`,
55
61
  type: 'test.job',
@@ -74,5 +80,30 @@ describe('JobsOutboxConsumer (Integration)', () => {
74
80
  const lengths = [res1.length, res2.length, res3.length].sort();
75
81
  expect(lengths).toEqual([0, 2, 2]);
76
82
  });
83
+ it('processItems() should push items and mark them as COMPLETED', async () => {
84
+ const testRepository = new TestJobsOutboxRepository(repository);
85
+ consumer = new JobsOutboxConsumer(logger, testRepository, 10, pusher);
86
+ const jobId = '00000000-0000-0000-0000-000000000010';
87
+ const item = repository.create({
88
+ id: jobId,
89
+ type: 'test.job',
90
+ emitter: 'test.service',
91
+ status: OutboxStatus.PROCESSING,
92
+ payload: { data: 'test' },
93
+ createdAt: new Date(),
94
+ updatedAt: new Date(),
95
+ scheduledAt: new Date(),
96
+ version: 1,
97
+ attempts: 0,
98
+ target: 'test.target',
99
+ });
100
+ await repository.save(item);
101
+ const entity = await testRepository.findOneOrFail({ id: jobId });
102
+ const pushSpy = jest.spyOn(pusher, 'pushElement');
103
+ await consumer.processItems([entity]);
104
+ expect(pushSpy).toHaveBeenCalledWith(expect.objectContaining({ id: jobId }));
105
+ const dbItem = await repository.findOneByOrFail({ id: jobId });
106
+ expect(dbItem.status).toBe(OutboxStatus.COMPLETED);
107
+ });
77
108
  });
78
109
  //# sourceMappingURL=jobs-outbox.consumer.int.spec.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"jobs-outbox.consumer.int.spec.js","sourceRoot":"","sources":["../../../../src/test/consumers/jobs/jobs-outbox.consumer.int.spec.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"jobs-outbox.consumer.int.spec.js","sourceRoot":"","sources":["../../../../src/test/consumers/jobs/jobs-outbox.consumer.int.spec.ts"],"names":[],"mappings":"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"}
@@ -6,10 +6,16 @@ import { OutboxStatus } from '@volontariapp/database';
6
6
  describe('JobsOutboxConsumer (Unit)', () => {
7
7
  let consumer;
8
8
  let repository;
9
+ let pusher;
9
10
  const logger = makeLoggerMock();
10
11
  beforeEach(() => {
11
12
  repository = makeJobsOutboxConsumerRepositoryMock();
12
- consumer = new JobsOutboxConsumer(logger, repository, 10);
13
+ pusher = {
14
+ pushElement: jest.fn().mockResolvedValue(undefined),
15
+ pushBulkElement: jest.fn().mockResolvedValue(undefined),
16
+ close: jest.fn().mockResolvedValue(undefined),
17
+ };
18
+ consumer = new JobsOutboxConsumer(logger, repository, 10, pusher);
13
19
  });
14
20
  afterEach(() => {
15
21
  jest.restoreAllMocks();
@@ -19,9 +25,7 @@ describe('JobsOutboxConsumer (Unit)', () => {
19
25
  });
20
26
  it('fetchPendingItems() should delegate to repository and return results', async () => {
21
27
  const mockEntities = [{ id: '1' }, { id: '2' }];
22
- const toEntitiesSpy = jest
23
- .spyOn(repository, 'toEntities')
24
- .mockReturnValue(mockEntities);
28
+ const toEntitiesSpy = jest.spyOn(repository, 'toEntities').mockReturnValue(mockEntities);
25
29
  const executeInTransactionSpy = jest.spyOn(repository, 'executeInTransaction');
26
30
  const result = await consumer.fetchPendingItems();
27
31
  expect(executeInTransactionSpy).toHaveBeenCalled();
@@ -29,7 +33,7 @@ describe('JobsOutboxConsumer (Unit)', () => {
29
33
  expect(result).toEqual(mockEntities);
30
34
  });
31
35
  describe('processItems', () => {
32
- it('should process items and mark them as completed', async () => {
36
+ it('should process items, push them and mark them as completed', async () => {
33
37
  const entities = [
34
38
  { id: '1', status: OutboxStatus.PROCESSING },
35
39
  { id: '2', status: OutboxStatus.PROCESSING },
@@ -38,10 +42,13 @@ describe('JobsOutboxConsumer (Unit)', () => {
38
42
  .outboxDispatcher;
39
43
  const completedSpy = jest.spyOn(dispatcher, 'markAsCompleted');
40
44
  await consumer.processItems(entities);
45
+ expect(pusher.pushElement).toHaveBeenCalledTimes(2);
46
+ expect(pusher.pushElement).toHaveBeenCalledWith(expect.objectContaining({ id: '1' }));
47
+ expect(pusher.pushElement).toHaveBeenCalledWith(expect.objectContaining({ id: '2' }));
41
48
  const spyMock = completedSpy;
42
49
  expect(spyMock).toHaveBeenCalledTimes(2);
43
- expect(spyMock).toHaveBeenCalledWith(entities[0]);
44
- expect(spyMock).toHaveBeenCalledWith(entities[1]);
50
+ expect(spyMock).toHaveBeenCalledWith(expect.objectContaining({ id: '1' }));
51
+ expect(spyMock).toHaveBeenCalledWith(expect.objectContaining({ id: '2' }));
45
52
  });
46
53
  });
47
54
  describe('markItemsAsCompleted', () => {
@@ -56,7 +63,7 @@ describe('JobsOutboxConsumer (Unit)', () => {
56
63
  await consumer.markItemsAsCompleted(entities);
57
64
  const spyMock = completedSpy;
58
65
  expect(spyMock).toHaveBeenCalledTimes(1);
59
- expect(spyMock).toHaveBeenCalledWith(entities[0]);
66
+ expect(spyMock).toHaveBeenCalledWith(expect.objectContaining({ id: '1' }));
60
67
  });
61
68
  });
62
69
  });
@@ -1 +1 @@
1
- {"version":3,"file":"jobs-outbox.consumer.unit.spec.js","sourceRoot":"","sources":["../../../../src/test/consumers/jobs/jobs-outbox.consumer.unit.spec.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"jobs-outbox.consumer.unit.spec.js","sourceRoot":"","sources":["../../../../src/test/consumers/jobs/jobs-outbox.consumer.unit.spec.ts"],"names":[],"mappings":"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"}
@@ -2,7 +2,7 @@ import { DataSource } from 'typeorm';
2
2
  import { EventQueueModel, JobsOutboxModel } from '@volontariapp/database';
3
3
  export const testDataSource = new DataSource({
4
4
  type: 'postgres',
5
- host: 'localhost',
5
+ host: '127.0.0.1',
6
6
  port: 5433,
7
7
  username: 'testuser',
8
8
  password: 'testpassword',
@@ -1 +1 @@
1
- {"version":3,"file":"global-setup.d.ts","sourceRoot":"","sources":["../../src/test/global-setup.ts"],"names":[],"mappings":";AAIA,wBA0BE"}
1
+ {"version":3,"file":"global-setup.d.ts","sourceRoot":"","sources":["../../src/test/global-setup.ts"],"names":[],"mappings":";AAKA,wBA+CE"}
@@ -1,8 +1,9 @@
1
1
  import { PostgresProvider } from '@volontariapp/bridge';
2
+ import { Redis } from 'ioredis';
2
3
  const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
3
4
  export default async () => {
4
5
  const provider = new PostgresProvider({
5
- host: 'localhost',
6
+ host: '127.0.0.1',
6
7
  port: 5433,
7
8
  username: 'testuser',
8
9
  password: 'testpassword',
@@ -15,12 +16,27 @@ export default async () => {
15
16
  const dataSource = provider.getDriver();
16
17
  await dataSource.query('SELECT 1');
17
18
  await provider.disconnect();
19
+ const redis = new Redis({
20
+ host: '127.0.0.1',
21
+ port: 6379,
22
+ connectTimeout: 1000,
23
+ retryStrategy: () => null,
24
+ });
25
+ redis.on('error', () => { });
26
+ try {
27
+ await redis.ping();
28
+ await redis.quit();
29
+ }
30
+ catch (err) {
31
+ await redis.quit().catch(() => undefined);
32
+ throw err;
33
+ }
18
34
  return;
19
35
  }
20
36
  catch {
21
37
  await provider.disconnect().catch(() => undefined);
22
38
  if (attempt === maxAttempts) {
23
- throw new Error('Test database is not reachable. Start it before running tests.');
39
+ throw new Error('Test database or Redis is not reachable. Start them before running tests.');
24
40
  }
25
41
  await sleep(500);
26
42
  }
@@ -1 +1 @@
1
- {"version":3,"file":"global-setup.js","sourceRoot":"","sources":["../../src/test/global-setup.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAExD,MAAM,KAAK,GAAG,CAAC,EAAU,EAAE,EAAE,CAAC,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC;AAEhF,eAAe,KAAK,IAAI,EAAE;IACxB,MAAM,QAAQ,GAAG,IAAI,gBAAgB,CAAC;QACpC,IAAI,EAAE,WAAW;QACjB,IAAI,EAAE,IAAI;QACV,QAAQ,EAAE,UAAU;QACpB,QAAQ,EAAE,cAAc;QACxB,QAAQ,EAAE,mBAAmB;KAC9B,CAAC,CAAC;IAEH,MAAM,WAAW,GAAG,EAAE,CAAC;IAEvB,KAAK,IAAI,OAAO,GAAG,CAAC,EAAE,OAAO,IAAI,WAAW,EAAE,OAAO,IAAI,CAAC,EAAE,CAAC;QAC3D,IAAI,CAAC;YACH,MAAM,QAAQ,CAAC,OAAO,EAAE,CAAC;YACzB,MAAM,UAAU,GAAG,QAAQ,CAAC,SAAS,EAAE,CAAC;YACxC,MAAM,UAAU,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;YACnC,MAAM,QAAQ,CAAC,UAAU,EAAE,CAAC;YAC5B,OAAO;QACT,CAAC;QAAC,MAAM,CAAC;YACP,MAAM,QAAQ,CAAC,UAAU,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;YACnD,IAAI,OAAO,KAAK,WAAW,EAAE,CAAC;gBAC5B,MAAM,IAAI,KAAK,CAAC,gEAAgE,CAAC,CAAC;YACpF,CAAC;YACD,MAAM,KAAK,CAAC,GAAG,CAAC,CAAC;QACnB,CAAC;IACH,CAAC;AACH,CAAC,CAAC"}
1
+ {"version":3,"file":"global-setup.js","sourceRoot":"","sources":["../../src/test/global-setup.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAEhC,MAAM,KAAK,GAAG,CAAC,EAAU,EAAE,EAAE,CAAC,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC;AAEhF,eAAe,KAAK,IAAI,EAAE;IACxB,MAAM,QAAQ,GAAG,IAAI,gBAAgB,CAAC;QACpC,IAAI,EAAE,WAAW;QACjB,IAAI,EAAE,IAAI;QACV,QAAQ,EAAE,UAAU;QACpB,QAAQ,EAAE,cAAc;QACxB,QAAQ,EAAE,mBAAmB;KAC9B,CAAC,CAAC;IAEH,MAAM,WAAW,GAAG,EAAE,CAAC;IAEvB,KAAK,IAAI,OAAO,GAAG,CAAC,EAAE,OAAO,IAAI,WAAW,EAAE,OAAO,IAAI,CAAC,EAAE,CAAC;QAC3D,IAAI,CAAC;YAEH,MAAM,QAAQ,CAAC,OAAO,EAAE,CAAC;YACzB,MAAM,UAAU,GAAG,QAAQ,CAAC,SAAS,EAAE,CAAC;YACxC,MAAM,UAAU,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;YACnC,MAAM,QAAQ,CAAC,UAAU,EAAE,CAAC;YAG5B,MAAM,KAAK,GAAG,IAAI,KAAK,CAAC;gBACtB,IAAI,EAAE,WAAW;gBACjB,IAAI,EAAE,IAAI;gBACV,cAAc,EAAE,IAAI;gBACpB,aAAa,EAAE,GAAG,EAAE,CAAC,IAAI;aAC1B,CAAC,CAAC;YACH,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;YAE5B,IAAI,CAAC;gBACH,MAAM,KAAK,CAAC,IAAI,EAAE,CAAC;gBACnB,MAAM,KAAK,CAAC,IAAI,EAAE,CAAC;YACrB,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,MAAM,KAAK,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;gBAC1C,MAAM,GAAG,CAAC;YACZ,CAAC;YAED,OAAO;QACT,CAAC;QAAC,MAAM,CAAC;YACP,MAAM,QAAQ,CAAC,UAAU,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;YACnD,IAAI,OAAO,KAAK,WAAW,EAAE,CAAC;gBAC5B,MAAM,IAAI,KAAK,CACb,2EAA2E,CAC5E,CAAC;YACJ,CAAC;YACD,MAAM,KAAK,CAAC,GAAG,CAAC,CAAC;QACnB,CAAC;IACH,CAAC;AACH,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=jobs-outbox.pusher.int.spec.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jobs-outbox.pusher.int.spec.d.ts","sourceRoot":"","sources":["../../../src/test/pushers/jobs-outbox.pusher.int.spec.ts"],"names":[],"mappings":""}
@@ -0,0 +1,104 @@
1
+ import { describe, expect, it, beforeEach, afterAll, afterEach } from '@jest/globals';
2
+ import { JobsOutboxPusher } from '../../pushers/jobs-outbox.pusher.js';
3
+ import { makeLoggerMock } from '../utils/helpers/logger-mock.helper.js';
4
+ import { makeJobsOutboxEvent } from '../utils/helpers/jobs-outbox-event.helper.js';
5
+ import { testRedisConfig, testRedisOptions, clearTestRedis } from '../redis-config.js';
6
+ import { Queue } from 'bullmq';
7
+ describe('JobsOutboxPusher (Integration)', () => {
8
+ let pusher;
9
+ const logger = makeLoggerMock();
10
+ beforeEach(async () => {
11
+ await clearTestRedis();
12
+ pusher = new JobsOutboxPusher(logger, testRedisConfig);
13
+ });
14
+ afterEach(async () => {
15
+ await pusher.close();
16
+ });
17
+ afterAll(async () => {
18
+ await clearTestRedis();
19
+ });
20
+ it('pushElement() should actually enqueue a job in Redis', async () => {
21
+ const target = 'integration-test-target';
22
+ const entity = makeJobsOutboxEvent({
23
+ id: 'int-1',
24
+ type: 'test.job',
25
+ payload: { foo: 'bar' },
26
+ target,
27
+ scheduledAt: undefined,
28
+ });
29
+ await pusher.pushElement(entity);
30
+ const inspectorQueue = new Queue(target, { connection: testRedisOptions });
31
+ try {
32
+ const job = await inspectorQueue.getJob('outbox-int-1');
33
+ expect(job).toBeDefined();
34
+ expect(job?.name).toBe('test.job');
35
+ expect(job?.data).toEqual({ foo: 'bar' });
36
+ }
37
+ finally {
38
+ await inspectorQueue.close();
39
+ }
40
+ });
41
+ it('pushBulkElement() should enqueue multiple jobs in Redis across targets', async () => {
42
+ const targetA = 'target-a';
43
+ const targetB = 'target-b';
44
+ const entities = [
45
+ makeJobsOutboxEvent({
46
+ id: 'bulk-1',
47
+ type: 'job.a1',
48
+ target: targetA,
49
+ payload: { p: 1 },
50
+ scheduledAt: undefined,
51
+ }),
52
+ makeJobsOutboxEvent({
53
+ id: 'bulk-2',
54
+ type: 'job.b1',
55
+ target: targetB,
56
+ payload: { p: 2 },
57
+ scheduledAt: undefined,
58
+ }),
59
+ makeJobsOutboxEvent({
60
+ id: 'bulk-3',
61
+ type: 'job.a2',
62
+ target: targetA,
63
+ payload: { p: 3 },
64
+ scheduledAt: undefined,
65
+ }),
66
+ ];
67
+ await pusher.pushBulkElement(entities);
68
+ const queueA = new Queue(targetA, { connection: testRedisOptions });
69
+ const queueB = new Queue(targetB, { connection: testRedisOptions });
70
+ try {
71
+ const job1 = await queueA.getJob('outbox-bulk-1');
72
+ const job3 = await queueA.getJob('outbox-bulk-3');
73
+ const job2 = await queueB.getJob('outbox-bulk-2');
74
+ expect(job1).toBeDefined();
75
+ expect(job3).toBeDefined();
76
+ expect(job2).toBeDefined();
77
+ }
78
+ finally {
79
+ await queueA.close();
80
+ await queueB.close();
81
+ }
82
+ });
83
+ it('should handle scheduled jobs with delay', async () => {
84
+ const target = 'delay-test-target';
85
+ const futureDate = new Date(Date.now() + 5000);
86
+ const entity = makeJobsOutboxEvent({
87
+ id: 'delayed-1',
88
+ target,
89
+ scheduledAt: futureDate,
90
+ });
91
+ await pusher.pushElement(entity);
92
+ const inspectorQueue = new Queue(target, { connection: testRedisOptions });
93
+ try {
94
+ const job = await inspectorQueue.getJob('outbox-delayed-1');
95
+ expect(job).toBeDefined();
96
+ const state = await job?.getState();
97
+ expect(state).toBe('delayed');
98
+ }
99
+ finally {
100
+ await inspectorQueue.close();
101
+ }
102
+ });
103
+ });
104
+ //# sourceMappingURL=jobs-outbox.pusher.int.spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jobs-outbox.pusher.int.spec.js","sourceRoot":"","sources":["../../../src/test/pushers/jobs-outbox.pusher.int.spec.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=jobs-outbox.pusher.unit.spec.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jobs-outbox.pusher.unit.spec.d.ts","sourceRoot":"","sources":["../../../src/test/pushers/jobs-outbox.pusher.unit.spec.ts"],"names":[],"mappings":""}
@@ -0,0 +1,102 @@
1
+ import { describe, expect, it, beforeEach, jest, afterEach } from '@jest/globals';
2
+ const mockQueueAdd = jest.fn();
3
+ const mockQueueAddBulk = jest.fn();
4
+ const mockQueueClose = jest.fn();
5
+ jest.unstable_mockModule('bullmq', () => ({
6
+ Queue: jest.fn().mockImplementation(() => ({
7
+ add: mockQueueAdd,
8
+ addBulk: mockQueueAddBulk,
9
+ close: mockQueueClose,
10
+ })),
11
+ }));
12
+ const { JobsOutboxPusher } = await import('../../pushers/jobs-outbox.pusher.js');
13
+ const { makeLoggerMock } = await import('../utils/helpers/logger-mock.helper.js');
14
+ const { makeJobsOutboxEvent } = await import('../utils/helpers/jobs-outbox-event.helper.js');
15
+ const { RedisConfig } = await import('@volontariapp/config');
16
+ describe('JobsOutboxPusher (Unit)', () => {
17
+ let pusher;
18
+ const loggerMock = makeLoggerMock();
19
+ const redisConfig = new RedisConfig();
20
+ redisConfig.host = 'localhost';
21
+ redisConfig.port = 6379;
22
+ beforeEach(() => {
23
+ jest.clearAllMocks();
24
+ pusher = new JobsOutboxPusher(loggerMock, redisConfig);
25
+ });
26
+ afterEach(async () => {
27
+ await pusher.close();
28
+ });
29
+ it('should be defined', () => {
30
+ expect(pusher).toBeDefined();
31
+ });
32
+ describe('pushElement', () => {
33
+ it('should push a job to the correct queue', async () => {
34
+ const entity = makeJobsOutboxEvent({
35
+ id: '1',
36
+ type: 'test.job',
37
+ payload: { data: 'test' },
38
+ target: 'test-service',
39
+ scheduledAt: undefined,
40
+ });
41
+ await pusher.pushElement(entity);
42
+ const { Queue } = await import('bullmq');
43
+ expect(Queue).toHaveBeenCalledWith('test-service', expect.any(Object));
44
+ expect(mockQueueAdd).toHaveBeenCalledWith('test.job', { data: 'test' }, { jobId: 'outbox-1' });
45
+ });
46
+ it('should include delay if scheduledAt is in the future', async () => {
47
+ const futureDate = new Date(Date.now() + 10000);
48
+ const entity = makeJobsOutboxEvent({
49
+ id: '1',
50
+ type: 'test.job',
51
+ payload: { data: 'test' },
52
+ target: 'test-service',
53
+ scheduledAt: futureDate,
54
+ });
55
+ await pusher.pushElement(entity);
56
+ expect(mockQueueAdd).toHaveBeenCalledWith('test.job', { data: 'test' }, expect.objectContaining({
57
+ delay: expect.any(Number),
58
+ jobId: 'outbox-1',
59
+ }));
60
+ });
61
+ });
62
+ describe('pushBulkElement', () => {
63
+ it('should group jobs by target and push them in bulk', async () => {
64
+ const entities = [
65
+ makeJobsOutboxEvent({
66
+ id: '1',
67
+ type: 'job.1',
68
+ payload: { p: 1 },
69
+ target: 'service-a',
70
+ scheduledAt: undefined,
71
+ }),
72
+ makeJobsOutboxEvent({
73
+ id: '2',
74
+ type: 'job.2',
75
+ payload: { p: 2 },
76
+ target: 'service-b',
77
+ scheduledAt: undefined,
78
+ }),
79
+ makeJobsOutboxEvent({
80
+ id: '3',
81
+ type: 'job.3',
82
+ payload: { p: 3 },
83
+ target: 'service-a',
84
+ scheduledAt: undefined,
85
+ }),
86
+ ];
87
+ await pusher.pushBulkElement(entities);
88
+ expect(mockQueueAddBulk).toHaveBeenCalledTimes(2);
89
+ const allBulkCalls = mockQueueAddBulk.mock.calls;
90
+ const serviceACall = allBulkCalls.find((call) => call[0].some((job) => job.name === 'job.1'));
91
+ expect(serviceACall).toBeDefined();
92
+ const [jobsA] = serviceACall;
93
+ expect(jobsA).toHaveLength(2);
94
+ expect(jobsA).toContainEqual({
95
+ name: 'job.1',
96
+ data: { p: 1 },
97
+ opts: { jobId: 'outbox-1' },
98
+ });
99
+ });
100
+ });
101
+ });
102
+ //# sourceMappingURL=jobs-outbox.pusher.unit.spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jobs-outbox.pusher.unit.spec.js","sourceRoot":"","sources":["../../../src/test/pushers/jobs-outbox.pusher.unit.spec.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ import type { RedisOptions } from 'ioredis';
2
+ import { Redis } from 'ioredis';
3
+ import type { RedisConfig } from '@volontariapp/config';
4
+ export declare const testRedisOptions: RedisOptions;
5
+ export declare const testRedisConfig: RedisConfig;
6
+ export declare const createTestRedisConnection: () => Redis;
7
+ export declare const clearTestRedis: () => Promise<void>;
8
+ //# sourceMappingURL=redis-config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"redis-config.d.ts","sourceRoot":"","sources":["../../src/test/redis-config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAC5C,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAExD,eAAO,MAAM,gBAAgB,EAAE,YAK9B,CAAC;AAEF,eAAO,MAAM,eAAe,EAIZ,WAAW,CAAC;AAE5B,eAAO,MAAM,yBAAyB,QAAO,KAE5C,CAAC;AAEF,eAAO,MAAM,cAAc,QAAa,OAAO,CAAC,IAAI,CAQnD,CAAC"}
@@ -0,0 +1,26 @@
1
+ import { Redis } from 'ioredis';
2
+ export const testRedisOptions = {
3
+ host: '127.0.0.1',
4
+ port: 6379,
5
+ maxRetriesPerRequest: null,
6
+ lazyConnect: true,
7
+ };
8
+ export const testRedisConfig = {
9
+ host: '127.0.0.1',
10
+ port: 6379,
11
+ dbIndex: 0,
12
+ };
13
+ export const createTestRedisConnection = () => {
14
+ return new Redis(testRedisOptions);
15
+ };
16
+ export const clearTestRedis = async () => {
17
+ const redis = createTestRedisConnection();
18
+ try {
19
+ await redis.connect();
20
+ await redis.flushall();
21
+ }
22
+ finally {
23
+ await redis.quit();
24
+ }
25
+ };
26
+ //# sourceMappingURL=redis-config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"redis-config.js","sourceRoot":"","sources":["../../src/test/redis-config.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAGhC,MAAM,CAAC,MAAM,gBAAgB,GAAiB;IAC5C,IAAI,EAAE,WAAW;IACjB,IAAI,EAAE,IAAI;IACV,oBAAoB,EAAE,IAAI;IAC1B,WAAW,EAAE,IAAI;CAClB,CAAC;AAEF,MAAM,CAAC,MAAM,eAAe,GAAG;IAC7B,IAAI,EAAE,WAAW;IACjB,IAAI,EAAE,IAAI;IACV,OAAO,EAAE,CAAC;CACe,CAAC;AAE5B,MAAM,CAAC,MAAM,yBAAyB,GAAG,GAAU,EAAE;IACnD,OAAO,IAAI,KAAK,CAAC,gBAAgB,CAAC,CAAC;AACrC,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,cAAc,GAAG,KAAK,IAAmB,EAAE;IACtD,MAAM,KAAK,GAAG,yBAAyB,EAAE,CAAC;IAC1C,IAAI,CAAC;QACH,MAAM,KAAK,CAAC,OAAO,EAAE,CAAC;QACtB,MAAM,KAAK,CAAC,QAAQ,EAAE,CAAC;IACzB,CAAC;YAAS,CAAC;QACT,MAAM,KAAK,CAAC,IAAI,EAAE,CAAC;IACrB,CAAC;AACH,CAAC,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@volontariapp/outbox",
3
- "version": "0.3.1",
3
+ "version": "0.4.0-snap-2c644e5",
4
4
  "publishConfig": {
5
5
  "access": "public",
6
6
  "provenance": true
@@ -37,9 +37,12 @@
37
37
  "db:down": "docker-compose -f ../../docker-compose.test.yml down"
38
38
  },
39
39
  "dependencies": {
40
- "@volontariapp/database": "1.12.0",
40
+ "@volontariapp/config": "2.1.0",
41
+ "@volontariapp/database": "1.13.0-snap-2c644e5",
41
42
  "@volontariapp/errors": "0.5.0",
42
- "@volontariapp/logger": "0.2.3"
43
+ "@volontariapp/logger": "0.2.3",
44
+ "bullmq": "^5.76.5",
45
+ "ioredis": "^5.10.1"
43
46
  },
44
47
  "devDependencies": {
45
48
  "@jest/globals": "^30.3.0",