@acmekit/event-bus-redis 2.13.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 ADDED
@@ -0,0 +1,79 @@
1
+ <p align="center">
2
+ <a href="https://www.acmekit.com">
3
+ <img alt="AcmeKit" src="https://user-images.githubusercontent.com/7554214/153162406-bf8fd16f-aa98-4604-b87b-e13ab4baf604.png" width="100" />
4
+ </a>
5
+ </p>
6
+ <h1 align="center">
7
+ @acmekit/event-bus-redis
8
+ </h1>
9
+
10
+ <h4 align="center">
11
+ <a href="https://docs.acmekit.com">Documentation</a> |
12
+ <a href="https://www.acmekit.com">Website</a>
13
+ </h4>
14
+
15
+ <p align="center">
16
+ An open source composable commerce engine built for developers.
17
+ </p>
18
+ <p align="center">
19
+ <a href="https://github.com/acmekit/acmekit/blob/master/LICENSE">
20
+ <img src="https://img.shields.io/badge/license-MIT-blue.svg" alt="AcmeKit is released under the MIT license." />
21
+ </a>
22
+ <a href="https://circleci.com/gh/acmekit/acmekit">
23
+ <img src="https://circleci.com/gh/acmekit/acmekit.svg?style=shield" alt="Current CircleCI build status." />
24
+ </a>
25
+ <a href="https://github.com/acmekit/acmekit/blob/master/CONTRIBUTING.md">
26
+ <img src="https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat" alt="PRs welcome!" />
27
+ </a>
28
+ <a href="https://www.producthunt.com/posts/acmekit"><img src="https://img.shields.io/badge/Product%20Hunt-%231%20Product%20of%20the%20Day-%23DA552E" alt="Product Hunt"></a>
29
+ <a href="https://discord.gg/xpCwq3Kfn8">
30
+ <img src="https://img.shields.io/badge/chat-on%20discord-7289DA.svg" alt="Discord Chat" />
31
+ </a>
32
+ <a href="https://twitter.com/intent/follow?screen_name=acmekit">
33
+ <img src="https://img.shields.io/twitter/follow/acmekit.svg?label=Follow%20@acmekit" alt="Follow @acmekit" />
34
+ </a>
35
+ </p>
36
+
37
+ ## Overview
38
+
39
+ Redis Event Bus module for AcmeKit. When installed, the events system of AcmeKit is powered by BullMQ and `io-redis`. BullMQ is responsible for the message queue and worker. `io-redis` is the underlying Redis client, that BullMQ connects to for events storage.
40
+
41
+ ## Getting started
42
+
43
+ Install the module:
44
+
45
+ ```bash
46
+ yarn add @acmekit/event-bus-redis
47
+ ```
48
+
49
+ Add the module to your `acmekit-config.js`:
50
+
51
+ ```js
52
+ module.exports = {
53
+ // ...
54
+ modules: [
55
+ {
56
+ resolve: "@acmekit/event-bus-redis",
57
+ options: {
58
+ redisUrl: "redis:..",
59
+ },
60
+ },
61
+ ],
62
+ // ...
63
+ }
64
+ ```
65
+
66
+ ## Configuration
67
+
68
+ The module can be configured with the following options:
69
+
70
+ | Option | Type | Description | Default |
71
+ | -------------- | --------- | ------------------------------------------------------------------------------------------------------------------------ | --------------- |
72
+ | `redisUrl` | `string` | URL of the Redis instance to connect to. | `events-worker` |
73
+ | `queueName` | `string?` | Name of the BullMQ queue. | `events-queue` |
74
+ | `queueOptions` | `object?` | Options for the BullMQ queue. See BullMQ's [documentation](https://api.docs.bullmq.io/interfaces/QueueOptions.html). | `{}` |
75
+ | `redisOptions` | `object?` | Options for the Redis instance. See `io-redis`'s [documentation](https://luin.github.io/ioredis/index.html#RedisOptions) | `{}` |
76
+
77
+ **Info**: See how the options are applied in the [RedisEventBusService](https://github.com/acmekit/acmekit/blob/0c1d1d590463fa30b083c4312293348bdf6596be/packages/event-bus-redis/src/services/event-bus-redis.ts#L52) and [loader](https://github.com/acmekit/acmekit/blob/0c1d1d590463fa30b083c4312293348bdf6596be/packages/event-bus-redis/src/loaders/index.ts).
78
+
79
+ If you do not provide a `redisUrl` in the module options, the server will fail to start.
@@ -0,0 +1,6 @@
1
+ import { ModuleExports } from "@acmekit/framework/types";
2
+ declare const moduleDefinition: ModuleExports;
3
+ export default moduleDefinition;
4
+ export * from "./initialize";
5
+ export * from "./types";
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAA;AAOxD,QAAA,MAAM,gBAAgB,EAAE,aAGvB,CAAA;AAED,eAAe,gBAAgB,CAAA;AAC/B,cAAc,cAAc,CAAA;AAC5B,cAAc,SAAS,CAAA"}
package/dist/index.js ADDED
@@ -0,0 +1,31 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ var __importDefault = (this && this.__importDefault) || function (mod) {
17
+ return (mod && mod.__esModule) ? mod : { "default": mod };
18
+ };
19
+ Object.defineProperty(exports, "__esModule", { value: true });
20
+ const loaders_1 = __importDefault(require("./loaders"));
21
+ const event_bus_redis_1 = __importDefault(require("./services/event-bus-redis"));
22
+ const service = event_bus_redis_1.default;
23
+ const loaders = [loaders_1.default];
24
+ const moduleDefinition = {
25
+ service,
26
+ loaders,
27
+ };
28
+ exports.default = moduleDefinition;
29
+ __exportStar(require("./initialize"), exports);
30
+ __exportStar(require("./types"), exports);
31
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;AACA,wDAA8B;AAC9B,iFAA6D;AAE7D,MAAM,OAAO,GAAG,yBAAoB,CAAA;AACpC,MAAM,OAAO,GAAG,CAAC,iBAAM,CAAC,CAAA;AAExB,MAAM,gBAAgB,GAAkB;IACtC,OAAO;IACP,OAAO;CACR,CAAA;AAED,kBAAe,gBAAgB,CAAA;AAC/B,+CAA4B;AAC5B,0CAAuB"}
@@ -0,0 +1,4 @@
1
+ import { ExternalModuleDeclaration, IEventBusService } from "@acmekit/framework/types";
2
+ import { EventBusRedisModuleOptions } from "../types";
3
+ export declare const initialize: (options?: EventBusRedisModuleOptions | ExternalModuleDeclaration) => Promise<IEventBusService>;
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/initialize/index.ts"],"names":[],"mappings":"AACA,OAAO,EACL,yBAAyB,EACzB,gBAAgB,EAEjB,MAAM,0BAA0B,CAAA;AAEjC,OAAO,EAAE,0BAA0B,EAAE,MAAM,UAAU,CAAA;AAErD,eAAO,MAAM,UAAU,GACrB,UAAU,0BAA0B,GAAG,yBAAyB,KAC/D,OAAO,CAAC,gBAAgB,CAW1B,CAAA"}
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.initialize = void 0;
4
+ const modules_sdk_1 = require("@acmekit/framework/modules-sdk");
5
+ const utils_1 = require("@acmekit/framework/utils");
6
+ const initialize = async (options) => {
7
+ const serviceKey = utils_1.Modules.EVENT_BUS;
8
+ const loaded = await modules_sdk_1.AcmeKitModule.bootstrap({
9
+ moduleKey: serviceKey,
10
+ defaultPath: "@acmekit/event-bus-redis",
11
+ declaration: options,
12
+ });
13
+ return loaded[serviceKey];
14
+ };
15
+ exports.initialize = initialize;
16
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/initialize/index.ts"],"names":[],"mappings":";;;AAAA,gEAA8D;AAM9D,oDAAkD;AAG3C,MAAM,UAAU,GAAG,KAAK,EAC7B,OAAgE,EACrC,EAAE;IAC7B,MAAM,UAAU,GAAG,eAAO,CAAC,SAAS,CAAA;IACpC,MAAM,MAAM,GAAG,MAAM,2BAAa,CAAC,SAAS,CAAmB;QAC7D,SAAS,EAAE,UAAU;QACrB,WAAW,EAAE,0BAA0B;QACvC,WAAW,EAAE,OAEgB;KAC9B,CAAC,CAAA;IAEF,OAAO,MAAM,CAAC,UAAU,CAAC,CAAA;AAC3B,CAAC,CAAA;AAbY,QAAA,UAAU,cAatB"}
@@ -0,0 +1,4 @@
1
+ import { LoaderOptions } from "@acmekit/framework/types";
2
+ declare const _default: ({ container, logger, options, }: LoaderOptions) => Promise<void>;
3
+ export default _default;
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/loaders/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAA;yBAKlC,iCAInB,aAAa,KAAG,OAAO,CAAC,IAAI,CAAC;AAJhC,wBA+CC"}
@@ -0,0 +1,39 @@
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
+ const awilix_1 = require("@acmekit/framework/awilix");
7
+ const ioredis_1 = __importDefault(require("ioredis"));
8
+ const os_1 = require("os");
9
+ exports.default = async ({ container, logger, options, }) => {
10
+ const { redisUrl, redisOptions, queueName, queueOptions, workerOptions, jobOptions, } = options;
11
+ if (!redisUrl) {
12
+ throw Error("No `redisUrl` provided in project config. It is required for the Redis Event Bus.");
13
+ }
14
+ const connection = new ioredis_1.default(redisUrl, {
15
+ // Required config. See: https://github.com/OptimalBits/bull/blob/develop/CHANGELOG.md#breaking-changes
16
+ maxRetriesPerRequest: null,
17
+ enableReadyCheck: false,
18
+ // Lazy connect to properly handle connection errors
19
+ lazyConnect: true,
20
+ ...(redisOptions ?? {}),
21
+ });
22
+ try {
23
+ await new Promise(async (resolve) => {
24
+ await connection.connect(resolve);
25
+ });
26
+ logger?.info(`Connection to Redis in module 'event-bus-redis' established`);
27
+ }
28
+ catch (err) {
29
+ logger?.error(`An error occurred while connecting to Redis in module 'event-bus-redis':${os_1.EOL} ${err}`);
30
+ }
31
+ container.register({
32
+ eventBusRedisConnection: (0, awilix_1.asValue)(connection),
33
+ eventBusRedisQueueName: (0, awilix_1.asValue)(queueName ?? "events-queue"),
34
+ eventBusRedisQueueOptions: (0, awilix_1.asValue)(queueOptions ?? {}),
35
+ eventBusRedisWorkerOptions: (0, awilix_1.asValue)(workerOptions ?? {}),
36
+ eventBusRedisJobOptions: (0, awilix_1.asValue)(jobOptions ?? {}),
37
+ });
38
+ };
39
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/loaders/index.ts"],"names":[],"mappings":";;;;;AAAA,sDAAmD;AAEnD,sDAA2B;AAC3B,2BAAwB;AAGxB,kBAAe,KAAK,EAAE,EACpB,SAAS,EACT,MAAM,EACN,OAAO,GACO,EAAiB,EAAE;IACjC,MAAM,EACJ,QAAQ,EACR,YAAY,EACZ,SAAS,EACT,YAAY,EACZ,aAAa,EACb,UAAU,GACX,GAAG,OAAqC,CAAA;IAEzC,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,MAAM,KAAK,CACT,mFAAmF,CACpF,CAAA;IACH,CAAC;IAED,MAAM,UAAU,GAAG,IAAI,iBAAK,CAAC,QAAQ,EAAE;QACrC,uGAAuG;QACvG,oBAAoB,EAAE,IAAI;QAC1B,gBAAgB,EAAE,KAAK;QACvB,oDAAoD;QACpD,WAAW,EAAE,IAAI;QACjB,GAAG,CAAC,YAAY,IAAI,EAAE,CAAC;KACxB,CAAC,CAAA;IAEF,IAAI,CAAC;QACH,MAAM,IAAI,OAAO,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE;YAClC,MAAM,UAAU,CAAC,OAAO,CAAC,OAAO,CAAC,CAAA;QACnC,CAAC,CAAC,CAAA;QACF,MAAM,EAAE,IAAI,CAAC,6DAA6D,CAAC,CAAA;IAC7E,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,EAAE,KAAK,CACX,2EAA2E,QAAG,IAAI,GAAG,EAAE,CACxF,CAAA;IACH,CAAC;IAED,SAAS,CAAC,QAAQ,CAAC;QACjB,uBAAuB,EAAE,IAAA,gBAAO,EAAC,UAAU,CAAC;QAC5C,sBAAsB,EAAE,IAAA,gBAAO,EAAC,SAAS,IAAI,cAAc,CAAC;QAC5D,yBAAyB,EAAE,IAAA,gBAAO,EAAC,YAAY,IAAI,EAAE,CAAC;QACtD,0BAA0B,EAAE,IAAA,gBAAO,EAAC,aAAa,IAAI,EAAE,CAAC;QACxD,uBAAuB,EAAE,IAAA,gBAAO,EAAC,UAAU,IAAI,EAAE,CAAC;KACnD,CAAC,CAAA;AACJ,CAAC,CAAA"}
@@ -0,0 +1,69 @@
1
+ import { InternalModuleDeclaration, Logger, Message } from "@acmekit/framework/types";
2
+ import { AbstractEventBusModuleService } from "@acmekit/framework/utils";
3
+ import { Queue, QueueOptions, Worker, WorkerOptions } from "bullmq";
4
+ import { Redis } from "ioredis";
5
+ import { BullJob, EmitOptions, EventBusRedisModuleOptions, Options } from "../types";
6
+ type InjectedDependencies = {
7
+ logger: Logger;
8
+ eventBusRedisConnection: Redis;
9
+ eventBusRedisQueueName: string;
10
+ eventBusRedisQueueOptions: Omit<QueueOptions, "connection">;
11
+ eventBusRedisWorkerOptions: Omit<WorkerOptions, "connection">;
12
+ eventBusRedisJobOptions: EmitOptions;
13
+ };
14
+ /**
15
+ * Can keep track of multiple subscribers to different events and run the
16
+ * subscribers when events happen. Events will run asynchronously.
17
+ */
18
+ export default class RedisEventBusService extends AbstractEventBusModuleService {
19
+ protected readonly logger_: Logger;
20
+ protected readonly eventBusRedisConnection_: Redis;
21
+ protected readonly queueName_: string;
22
+ protected readonly queueOptions_: Omit<QueueOptions, "connection">;
23
+ protected readonly workerOptions_: Omit<WorkerOptions, "connection">;
24
+ protected readonly jobOptions_: EmitOptions;
25
+ protected queue_: Queue;
26
+ protected bullWorker_: Worker;
27
+ constructor({ logger, eventBusRedisConnection, eventBusRedisQueueName, eventBusRedisQueueOptions, eventBusRedisWorkerOptions, eventBusRedisJobOptions, }: InjectedDependencies, _moduleOptions: EventBusRedisModuleOptions | undefined, _moduleDeclaration: InternalModuleDeclaration);
28
+ __hooks: {
29
+ onApplicationStart: () => Promise<void>;
30
+ onApplicationShutdown: () => Promise<void>;
31
+ onApplicationPrepareShutdown: () => Promise<void>;
32
+ };
33
+ /**
34
+ * Build events for queue processing with priority handling.
35
+ *
36
+ * Priority levels (lower number = higher priority):
37
+ * - 10: Critical business events (e.g., order placed)
38
+ * - 100: Default priority for normal events (default)
39
+ * - 2,097,152: Lowest priority for internal events
40
+ *
41
+ * Priority override hierarchy (highest to lowest precedence):
42
+ * 1. Message-level options (eventData.options.priority)
43
+ * 2. Emit-level options (options.priority)
44
+ * 3. Module-level job options (this.jobOptions_.priority)
45
+ * 4. Internal flag default (options.internal ? EventPriority.LOWEST : EventPriority.DEFAULT)
46
+ */
47
+ private buildEvents;
48
+ /**
49
+ * Emit a single or number of events
50
+ * @param eventsData
51
+ * @param options
52
+ */
53
+ emit<T = unknown>(eventsData: Message<T> | Message<T>[], options?: Options): Promise<void>;
54
+ private setExpire;
55
+ private groupEvents;
56
+ private getGroupedEvents;
57
+ releaseGroupedEvents(eventGroupId: string): Promise<void>;
58
+ clearGroupedEvents(eventGroupId: string, { eventNames, }?: {
59
+ eventNames?: string[];
60
+ }): Promise<void>;
61
+ /**
62
+ * Handles incoming jobs.
63
+ * @param job The job object
64
+ * @return resolves to the results of the subscriber calls.
65
+ */
66
+ worker_: <T>(job: BullJob<T>) => Promise<unknown>;
67
+ }
68
+ export {};
69
+ //# sourceMappingURL=event-bus-redis.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"event-bus-redis.d.ts","sourceRoot":"","sources":["../../src/services/event-bus-redis.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,yBAAyB,EACzB,MAAM,EACN,OAAO,EACR,MAAM,0BAA0B,CAAA;AACjC,OAAO,EACL,6BAA6B,EAI9B,MAAM,0BAA0B,CAAA;AACjC,OAAO,EAEL,KAAK,EACL,YAAY,EACZ,MAAM,EACN,aAAa,EACd,MAAM,QAAQ,CAAA;AACf,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAA;AAC/B,OAAO,EACL,OAAO,EACP,WAAW,EACX,0BAA0B,EAC1B,OAAO,EACR,MAAM,UAAU,CAAA;AAEjB,KAAK,oBAAoB,GAAG;IAC1B,MAAM,EAAE,MAAM,CAAA;IACd,uBAAuB,EAAE,KAAK,CAAA;IAC9B,sBAAsB,EAAE,MAAM,CAAA;IAC9B,yBAAyB,EAAE,IAAI,CAAC,YAAY,EAAE,YAAY,CAAC,CAAA;IAC3D,0BAA0B,EAAE,IAAI,CAAC,aAAa,EAAE,YAAY,CAAC,CAAA;IAC7D,uBAAuB,EAAE,WAAW,CAAA;CACrC,CAAA;AAQD;;;GAGG;AAEH,MAAM,CAAC,OAAO,OAAO,oBAAqB,SAAQ,6BAA6B;IAC7E,SAAS,CAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IAClC,SAAS,CAAC,QAAQ,CAAC,wBAAwB,EAAE,KAAK,CAAA;IAElD,SAAS,CAAC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;IACrC,SAAS,CAAC,QAAQ,CAAC,aAAa,EAAE,IAAI,CAAC,YAAY,EAAE,YAAY,CAAC,CAAA;IAClE,SAAS,CAAC,QAAQ,CAAC,cAAc,EAAE,IAAI,CAAC,aAAa,EAAE,YAAY,CAAC,CAAA;IACpE,SAAS,CAAC,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAA;IAI3C,SAAS,CAAC,MAAM,EAAE,KAAK,CAAA;IACvB,SAAS,CAAC,WAAW,EAAE,MAAM,CAAA;gBAG3B,EACE,MAAM,EACN,uBAAuB,EACvB,sBAAsB,EACtB,yBAAyB,EACzB,0BAA0B,EAC1B,uBAAuB,GACxB,EAAE,oBAAoB,EACvB,cAAc,EAAE,0BAA0B,YAAK,EAC/C,kBAAkB,EAAE,yBAAyB;IAmC/C,OAAO;;;;MAYN;IAED;;;;;;;;;;;;;OAaG;IACH,OAAO,CAAC,WAAW;IAuDnB;;;;OAIG;IACG,IAAI,CAAC,CAAC,GAAG,OAAO,EACpB,UAAU,EAAE,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,EAAE,EACrC,OAAO,GAAE,OAAY,GACpB,OAAO,CAAC,IAAI,CAAC;YA+DF,SAAS;YAQT,WAAW;YAUX,gBAAgB;IAUxB,oBAAoB,CAAC,YAAY,EAAE,MAAM;IA+BzC,kBAAkB,CACtB,YAAY,EAAE,MAAM,EACpB,EACE,UAAU,GACX,GAAE;QACD,UAAU,CAAC,EAAE,MAAM,EAAE,CAAA;KACjB;IAwCR;;;;OAIG;IACH,OAAO,GAAU,CAAC,EAAE,KAAK,OAAO,CAAC,CAAC,CAAC,KAAG,OAAO,CAAC,OAAO,CAAC,CAsGrD;CACF"}
@@ -0,0 +1,296 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const utils_1 = require("@acmekit/framework/utils");
4
+ const bullmq_1 = require("bullmq");
5
+ /**
6
+ * Can keep track of multiple subscribers to different events and run the
7
+ * subscribers when events happen. Events will run asynchronously.
8
+ */
9
+ // eslint-disable-next-line max-len
10
+ class RedisEventBusService extends utils_1.AbstractEventBusModuleService {
11
+ constructor({ logger, eventBusRedisConnection, eventBusRedisQueueName, eventBusRedisQueueOptions, eventBusRedisWorkerOptions, eventBusRedisJobOptions, }, _moduleOptions = {}, _moduleDeclaration) {
12
+ // @ts-ignore
13
+ super(...arguments);
14
+ this.__hooks = {
15
+ onApplicationStart: async () => {
16
+ await this.bullWorker_?.run();
17
+ },
18
+ onApplicationShutdown: async () => {
19
+ await this.queue_.close();
20
+ // eslint-disable-next-line max-len
21
+ this.eventBusRedisConnection_.disconnect();
22
+ },
23
+ onApplicationPrepareShutdown: async () => {
24
+ await this.bullWorker_?.close();
25
+ },
26
+ };
27
+ /**
28
+ * Handles incoming jobs.
29
+ * @param job The job object
30
+ * @return resolves to the results of the subscriber calls.
31
+ */
32
+ this.worker_ = async (job) => {
33
+ const { data, name, opts } = job;
34
+ const eventSubscribers = this.eventToSubscribersMap.get(name) || [];
35
+ const wildcardSubscribers = this.eventToSubscribersMap.get("*") || [];
36
+ const allSubscribers = eventSubscribers.concat(wildcardSubscribers);
37
+ // Pull already completed subscribers from the job data
38
+ const completedSubscribers = job.data.completedSubscriberIds || [];
39
+ // Filter out already completed subscribers from the all subscribers
40
+ const subscribersInCurrentAttempt = allSubscribers.filter((subscriber) => subscriber.id && !completedSubscribers.includes(subscriber.id));
41
+ const currentAttempt = job.attemptsMade;
42
+ const isRetry = currentAttempt > 1;
43
+ const configuredAttempts = job.opts.attempts;
44
+ const isFinalAttempt = currentAttempt === configuredAttempts;
45
+ if (!opts.internal) {
46
+ if (isRetry) {
47
+ if (isFinalAttempt) {
48
+ this.logger_.info(`Final retry attempt for ${name}`);
49
+ }
50
+ this.logger_.info(`Retrying ${name} which has ${eventSubscribers.length} subscribers (${subscribersInCurrentAttempt.length} of them failed)`);
51
+ }
52
+ else {
53
+ const prioirityInfo = opts.priority != undefined ? ` (priority: ${opts.priority})` : "";
54
+ this.logger_.info(`Processing ${name}${prioirityInfo} which has ${eventSubscribers.length} subscribers`);
55
+ }
56
+ }
57
+ const completedSubscribersInCurrentAttempt = [];
58
+ const subscribersResult = await Promise.all(subscribersInCurrentAttempt.map(async ({ id, subscriber }) => {
59
+ // De-serialize the event data and metadata from a single field into the original format expected by the subscribers
60
+ const event = {
61
+ name,
62
+ data: data.data,
63
+ metadata: data.metadata,
64
+ };
65
+ try {
66
+ return await subscriber(event).then((data) => {
67
+ // For every subscriber that completes successfully, add their id to the list of completed subscribers
68
+ completedSubscribersInCurrentAttempt.push(id);
69
+ return data;
70
+ });
71
+ }
72
+ catch (err) {
73
+ this.logger_?.warn(`An error occurred while processing ${name}:`);
74
+ this.logger_?.warn(err);
75
+ return err;
76
+ }
77
+ }));
78
+ // If the number of completed subscribers is different from the number of subcribers to process in current attempt, some of them failed
79
+ const didSubscribersFail = completedSubscribersInCurrentAttempt.length !==
80
+ subscribersInCurrentAttempt.length;
81
+ const isRetriesConfigured = configuredAttempts > 1;
82
+ // Therefore, if retrying is configured, we try again
83
+ const shouldRetry = didSubscribersFail && isRetriesConfigured && !isFinalAttempt;
84
+ if (shouldRetry) {
85
+ const updatedCompletedSubscribers = [
86
+ ...completedSubscribers,
87
+ ...completedSubscribersInCurrentAttempt,
88
+ ];
89
+ job.data.completedSubscriberIds = updatedCompletedSubscribers;
90
+ await job.updateData(job.data);
91
+ const errorMessage = `One or more subscribers of ${name} failed. Retrying...`;
92
+ this.logger_.warn(errorMessage);
93
+ throw Error(errorMessage);
94
+ }
95
+ if (didSubscribersFail && !isFinalAttempt) {
96
+ // If retrying is not configured, we log a warning to allow server admins to recover manually
97
+ this.logger_.warn(`One or more subscribers of ${name} failed. Retrying is not configured. Use 'attempts' option when emitting events.`);
98
+ }
99
+ return subscribersResult;
100
+ };
101
+ this.eventBusRedisConnection_ = eventBusRedisConnection;
102
+ this.logger_ = logger;
103
+ this.queueName_ = eventBusRedisQueueName ?? "events-queue";
104
+ this.queueOptions_ = eventBusRedisQueueOptions ?? {};
105
+ this.workerOptions_ = eventBusRedisWorkerOptions ?? {};
106
+ this.jobOptions_ = eventBusRedisJobOptions ?? {};
107
+ // TODO: Comment temporarely and we will re enable it in the near future #14478
108
+ // this.eventOptions_ =
109
+ // _moduleOptions.eventOptions ??
110
+ // _moduleDeclaration.options?.eventOptions ??
111
+ // {}
112
+ this.queue_ = new bullmq_1.Queue(this.queueName_, {
113
+ prefix: `${this.constructor.name}`,
114
+ ...this.queueOptions_,
115
+ connection: eventBusRedisConnection,
116
+ });
117
+ // Register our worker to handle emit calls
118
+ if (this.isWorkerMode) {
119
+ this.bullWorker_ = new bullmq_1.Worker(this.queueName_, this.worker_, {
120
+ prefix: `${this.constructor.name}`,
121
+ ...this.workerOptions_,
122
+ connection: eventBusRedisConnection,
123
+ autorun: false,
124
+ });
125
+ }
126
+ }
127
+ /**
128
+ * Build events for queue processing with priority handling.
129
+ *
130
+ * Priority levels (lower number = higher priority):
131
+ * - 10: Critical business events (e.g., order placed)
132
+ * - 100: Default priority for normal events (default)
133
+ * - 2,097,152: Lowest priority for internal events
134
+ *
135
+ * Priority override hierarchy (highest to lowest precedence):
136
+ * 1. Message-level options (eventData.options.priority)
137
+ * 2. Emit-level options (options.priority)
138
+ * 3. Module-level job options (this.jobOptions_.priority)
139
+ * 4. Internal flag default (options.internal ? EventPriority.LOWEST : EventPriority.DEFAULT)
140
+ */
141
+ buildEvents(eventsData, options = {}) {
142
+ const opts = {
143
+ // default options
144
+ removeOnComplete: true,
145
+ attempts: 1,
146
+ priority: options.internal ? utils_1.EventPriority.LOWEST : utils_1.EventPriority.DEFAULT,
147
+ // global options
148
+ ...this.jobOptions_,
149
+ ...options,
150
+ };
151
+ return eventsData.map((eventData) => {
152
+ // We want to preserve event data + metadata. However, bullmq only allows for a single data field.
153
+ // Therefore, upon adding jobs to the queue we will serialize the event data and metadata into a single field
154
+ // and upon processing the job, we will deserialize it back into the original format expected by the subscribers.
155
+ const event = {
156
+ data: eventData.data,
157
+ metadata: eventData.metadata,
158
+ };
159
+ const finalOptions = {
160
+ ...opts,
161
+ ...eventData.options,
162
+ };
163
+ // TODO: Comment temporarely and we will re enable it in the near future #14478
164
+ // finalOptions.priority =
165
+ // eventData.options?.priority ??
166
+ // this.eventOptions_[eventData.name]?.priority
167
+ if (finalOptions.priority != undefined &&
168
+ (finalOptions.priority < 1 ||
169
+ finalOptions.priority > utils_1.EventPriority.LOWEST)) {
170
+ this.logger_.warn(`Invalid priority value: ${finalOptions.priority} for event ${eventData.name}. Must be between 1 and ${utils_1.EventPriority.LOWEST}`);
171
+ finalOptions.priority = utils_1.EventPriority.DEFAULT;
172
+ this.logger_.warn(`Setting priority to default value: ${utils_1.EventPriority.DEFAULT} for event ${eventData.name}`);
173
+ }
174
+ return {
175
+ data: event,
176
+ name: eventData.name,
177
+ opts: finalOptions,
178
+ };
179
+ });
180
+ }
181
+ /**
182
+ * Emit a single or number of events
183
+ * @param eventsData
184
+ * @param options
185
+ */
186
+ async emit(eventsData, options = {}) {
187
+ let eventsDataArray = Array.isArray(eventsData) ? eventsData : [eventsData];
188
+ const { groupedEventsTTL = 600 } = options;
189
+ delete options.groupedEventsTTL;
190
+ const eventsToEmit = eventsDataArray.filter((eventData) => !(0, utils_1.isPresent)(eventData.metadata?.eventGroupId));
191
+ const eventsToGroup = eventsDataArray.filter((eventData) => (0, utils_1.isPresent)(eventData.metadata?.eventGroupId));
192
+ const groupEventsMap = new Map();
193
+ for (const event of eventsToGroup) {
194
+ const groupId = event.metadata?.eventGroupId;
195
+ const groupEvents = groupEventsMap.get(groupId) ?? [];
196
+ groupEvents.push(event);
197
+ groupEventsMap.set(groupId, groupEvents);
198
+ }
199
+ const promises = [];
200
+ if (eventsToEmit.length) {
201
+ eventsToEmit.map((eventData) => this.callInterceptors(eventData, { isGrouped: false }));
202
+ const eventsWithSubscribers = eventsToEmit.filter((eventData) => {
203
+ const eventSubscribers = this.eventToSubscribersMap.get(eventData.name) || [];
204
+ const wildcardSubscribers = this.eventToSubscribersMap.get("*") || [];
205
+ return eventSubscribers.length || wildcardSubscribers.length;
206
+ });
207
+ if (eventsWithSubscribers.length) {
208
+ const emitData = this.buildEvents(eventsWithSubscribers, options);
209
+ promises.push(this.queue_.addBulk(emitData));
210
+ }
211
+ }
212
+ for (const [groupId, events] of groupEventsMap.entries()) {
213
+ if (!events?.length) {
214
+ continue;
215
+ }
216
+ // Set a TTL for the key of the list that is scoped to a group
217
+ // This will be helpful in preventing stale data from staying in redis for too long
218
+ // in the event the module fails to cleanup events. For long running workflows, setting a much higher
219
+ // TTL or even skipping the TTL would be required
220
+ void this.setExpire(groupId, groupedEventsTTL);
221
+ const eventsData = this.buildEvents(events, options);
222
+ promises.push(this.groupEvents(groupId, eventsData));
223
+ }
224
+ await (0, utils_1.promiseAll)(promises);
225
+ }
226
+ async setExpire(eventGroupId, ttl) {
227
+ if (!eventGroupId) {
228
+ return;
229
+ }
230
+ await this.eventBusRedisConnection_.expire(`staging:${eventGroupId}`, ttl);
231
+ }
232
+ async groupEvents(eventGroupId, events) {
233
+ await this.eventBusRedisConnection_.rpush(`staging:${eventGroupId}`, ...events.map((event) => JSON.stringify(event)));
234
+ }
235
+ async getGroupedEvents(eventGroupId) {
236
+ return await this.eventBusRedisConnection_
237
+ .lrange(`staging:${eventGroupId}`, 0, -1)
238
+ .then((result) => {
239
+ return result.map((jsonString) => JSON.parse(jsonString));
240
+ });
241
+ }
242
+ async releaseGroupedEvents(eventGroupId) {
243
+ const groupedEvents = await this.getGroupedEvents(eventGroupId);
244
+ // Call interceptors before emitting grouped events
245
+ // Extract the original messages from the job data structure
246
+ groupedEvents.map((jobData) => {
247
+ const message = {
248
+ name: jobData.name,
249
+ data: jobData.data,
250
+ metadata: jobData.data.metadata,
251
+ };
252
+ this.callInterceptors(message, {
253
+ isGrouped: true,
254
+ eventGroupId,
255
+ });
256
+ });
257
+ const eventsWithSubscribers = groupedEvents.filter((jobData) => {
258
+ const eventSubscribers = this.eventToSubscribersMap.get(jobData.name) || [];
259
+ const wildcardSubscribers = this.eventToSubscribersMap.get("*") || [];
260
+ return eventSubscribers.length || wildcardSubscribers.length;
261
+ });
262
+ if (eventsWithSubscribers.length) {
263
+ await this.queue_.addBulk(eventsWithSubscribers);
264
+ }
265
+ await this.clearGroupedEvents(eventGroupId);
266
+ }
267
+ async clearGroupedEvents(eventGroupId, { eventNames, } = {}) {
268
+ if (!eventGroupId) {
269
+ return;
270
+ }
271
+ if (eventNames?.length) {
272
+ /**
273
+ * If any event names are provided, we keep all events except the ones that match the event
274
+ * names. which allow to partially clear an event group.
275
+ */
276
+ const eventsToKeep = await this.eventBusRedisConnection_
277
+ .lrange(`staging:${eventGroupId}`, 0, -1)
278
+ .then((result) => {
279
+ return result
280
+ .map((jsonString) => JSON.parse(jsonString))
281
+ .filter((event) => !eventNames.includes(event.name));
282
+ });
283
+ // Create a pipeline
284
+ const pipeline = this.eventBusRedisConnection_.pipeline();
285
+ // Empty the current list
286
+ pipeline.del(`staging:${eventGroupId}`);
287
+ // Add the remaining events to the list
288
+ pipeline.rpush(`staging:${eventGroupId}`, ...eventsToKeep.map((event) => JSON.stringify(event)));
289
+ await pipeline.exec();
290
+ return;
291
+ }
292
+ await this.eventBusRedisConnection_.unlink(`staging:${eventGroupId}`);
293
+ }
294
+ }
295
+ exports.default = RedisEventBusService;
296
+ //# sourceMappingURL=event-bus-redis.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"event-bus-redis.js","sourceRoot":"","sources":["../../src/services/event-bus-redis.ts"],"names":[],"mappings":";;AAQA,oDAKiC;AACjC,mCAMe;AAwBf;;;GAGG;AACH,mCAAmC;AACnC,MAAqB,oBAAqB,SAAQ,qCAA6B;IAc7E,YACE,EACE,MAAM,EACN,uBAAuB,EACvB,sBAAsB,EACtB,yBAAyB,EACzB,0BAA0B,EAC1B,uBAAuB,GACF,EACvB,iBAA6C,EAAE,EAC/C,kBAA6C;QAE7C,aAAa;QACb,KAAK,CAAC,GAAG,SAAS,CAAC,CAAA;QAgCrB,YAAO,GAAG;YACR,kBAAkB,EAAE,KAAK,IAAI,EAAE;gBAC7B,MAAM,IAAI,CAAC,WAAW,EAAE,GAAG,EAAE,CAAA;YAC/B,CAAC;YACD,qBAAqB,EAAE,KAAK,IAAI,EAAE;gBAChC,MAAM,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAA;gBACzB,mCAAmC;gBACnC,IAAI,CAAC,wBAAwB,CAAC,UAAU,EAAE,CAAA;YAC5C,CAAC;YACD,4BAA4B,EAAE,KAAK,IAAI,EAAE;gBACvC,MAAM,IAAI,CAAC,WAAW,EAAE,KAAK,EAAE,CAAA;YACjC,CAAC;SACF,CAAA;QAuPD;;;;WAIG;QACH,YAAO,GAAG,KAAK,EAAK,GAAe,EAAoB,EAAE;YACvD,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,GAAG,CAAA;YAChC,MAAM,gBAAgB,GAAG,IAAI,CAAC,qBAAqB,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,CAAA;YACnE,MAAM,mBAAmB,GAAG,IAAI,CAAC,qBAAqB,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,CAAA;YAErE,MAAM,cAAc,GAAG,gBAAgB,CAAC,MAAM,CAAC,mBAAmB,CAAC,CAAA;YAEnE,uDAAuD;YACvD,MAAM,oBAAoB,GAAG,GAAG,CAAC,IAAI,CAAC,sBAAsB,IAAI,EAAE,CAAA;YAElE,oEAAoE;YACpE,MAAM,2BAA2B,GAAG,cAAc,CAAC,MAAM,CACvD,CAAC,UAAU,EAAE,EAAE,CACb,UAAU,CAAC,EAAE,IAAI,CAAC,oBAAoB,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC,CACjE,CAAA;YAED,MAAM,cAAc,GAAG,GAAG,CAAC,YAAY,CAAA;YACvC,MAAM,OAAO,GAAG,cAAc,GAAG,CAAC,CAAA;YAClC,MAAM,kBAAkB,GAAG,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAA;YAE5C,MAAM,cAAc,GAAG,cAAc,KAAK,kBAAkB,CAAA;YAE5D,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC;gBACnB,IAAI,OAAO,EAAE,CAAC;oBACZ,IAAI,cAAc,EAAE,CAAC;wBACnB,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,2BAA2B,IAAI,EAAE,CAAC,CAAA;oBACtD,CAAC;oBAED,IAAI,CAAC,OAAO,CAAC,IAAI,CACf,YAAY,IAAI,cAAc,gBAAgB,CAAC,MAAM,iBAAiB,2BAA2B,CAAC,MAAM,kBAAkB,CAC3H,CAAA;gBACH,CAAC;qBAAM,CAAC;oBACN,MAAM,aAAa,GACjB,IAAI,CAAC,QAAQ,IAAI,SAAS,CAAC,CAAC,CAAC,eAAe,IAAI,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAC,EAAE,CAAA;oBACnE,IAAI,CAAC,OAAO,CAAC,IAAI,CACf,cAAc,IAAI,GAAG,aAAa,cAAc,gBAAgB,CAAC,MAAM,cAAc,CACtF,CAAA;gBACH,CAAC;YACH,CAAC;YAED,MAAM,oCAAoC,GAAa,EAAE,CAAA;YAEzD,MAAM,iBAAiB,GAAG,MAAM,OAAO,CAAC,GAAG,CACzC,2BAA2B,CAAC,GAAG,CAAC,KAAK,EAAE,EAAE,EAAE,EAAE,UAAU,EAAE,EAAE,EAAE;gBAC3D,oHAAoH;gBACpH,MAAM,KAAK,GAAG;oBACZ,IAAI;oBACJ,IAAI,EAAE,IAAI,CAAC,IAAI;oBACf,QAAQ,EAAE,IAAI,CAAC,QAAQ;iBACxB,CAAA;gBAED,IAAI,CAAC;oBACH,OAAO,MAAM,UAAU,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE;wBAC3C,sGAAsG;wBACtG,oCAAoC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;wBAC7C,OAAO,IAAI,CAAA;oBACb,CAAC,CAAC,CAAA;gBACJ,CAAC;gBAAC,OAAO,GAAG,EAAE,CAAC;oBACb,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,sCAAsC,IAAI,GAAG,CAAC,CAAA;oBACjE,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,GAAG,CAAC,CAAA;oBAEvB,OAAO,GAAG,CAAA;gBACZ,CAAC;YACH,CAAC,CAAC,CACH,CAAA;YAED,uIAAuI;YACvI,MAAM,kBAAkB,GACtB,oCAAoC,CAAC,MAAM;gBAC3C,2BAA2B,CAAC,MAAM,CAAA;YAEpC,MAAM,mBAAmB,GAAG,kBAAmB,GAAG,CAAC,CAAA;YAEnD,qDAAqD;YACrD,MAAM,WAAW,GACf,kBAAkB,IAAI,mBAAmB,IAAI,CAAC,cAAc,CAAA;YAE9D,IAAI,WAAW,EAAE,CAAC;gBAChB,MAAM,2BAA2B,GAAG;oBAClC,GAAG,oBAAoB;oBACvB,GAAG,oCAAoC;iBACxC,CAAA;gBAED,GAAG,CAAC,IAAI,CAAC,sBAAsB,GAAG,2BAA2B,CAAA;gBAE7D,MAAM,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;gBAE9B,MAAM,YAAY,GAAG,8BAA8B,IAAI,sBAAsB,CAAA;gBAE7E,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,YAAY,CAAC,CAAA;gBAE/B,MAAM,KAAK,CAAC,YAAY,CAAC,CAAA;YAC3B,CAAC;YAED,IAAI,kBAAkB,IAAI,CAAC,cAAc,EAAE,CAAC;gBAC1C,6FAA6F;gBAC7F,IAAI,CAAC,OAAO,CAAC,IAAI,CACf,8BAA8B,IAAI,kFAAkF,CACrH,CAAA;YACH,CAAC;YAED,OAAO,iBAAiB,CAAA;QAC1B,CAAC,CAAA;QA5YC,IAAI,CAAC,wBAAwB,GAAG,uBAAuB,CAAA;QACvD,IAAI,CAAC,OAAO,GAAG,MAAM,CAAA;QAErB,IAAI,CAAC,UAAU,GAAG,sBAAsB,IAAI,cAAc,CAAA;QAC1D,IAAI,CAAC,aAAa,GAAG,yBAAyB,IAAI,EAAE,CAAA;QACpD,IAAI,CAAC,cAAc,GAAG,0BAA0B,IAAI,EAAE,CAAA;QACtD,IAAI,CAAC,WAAW,GAAG,uBAAuB,IAAI,EAAE,CAAA;QAChD,+EAA+E;QAC/E,uBAAuB;QACvB,mCAAmC;QACnC,gDAAgD;QAChD,OAAO;QAEP,IAAI,CAAC,MAAM,GAAG,IAAI,cAAK,CAAC,IAAI,CAAC,UAAU,EAAE;YACvC,MAAM,EAAE,GAAG,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE;YAClC,GAAG,IAAI,CAAC,aAAa;YACrB,UAAU,EAAE,uBAAuB;SACpC,CAAC,CAAA;QAEF,2CAA2C;QAC3C,IAAI,IAAI,CAAC,YAAY,EAAE,CAAC;YACtB,IAAI,CAAC,WAAW,GAAG,IAAI,eAAM,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,OAAO,EAAE;gBAC3D,MAAM,EAAE,GAAG,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE;gBAClC,GAAG,IAAI,CAAC,cAAc;gBACtB,UAAU,EAAE,uBAAuB;gBACnC,OAAO,EAAE,KAAK;aACf,CAAC,CAAA;QACJ,CAAC;IACH,CAAC;IAgBD;;;;;;;;;;;;;OAaG;IACK,WAAW,CACjB,UAAwB,EACxB,UAAmB,EAAE;QAErB,MAAM,IAAI,GAAG;YACX,kBAAkB;YAClB,gBAAgB,EAAE,IAAI;YACtB,QAAQ,EAAE,CAAC;YACX,QAAQ,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,qBAAa,CAAC,MAAM,CAAC,CAAC,CAAC,qBAAa,CAAC,OAAO;YACzE,iBAAiB;YACjB,GAAG,IAAI,CAAC,WAAW;YACnB,GAAG,OAAO;SACX,CAAA;QAED,OAAO,UAAU,CAAC,GAAG,CAAC,CAAC,SAAS,EAAE,EAAE;YAClC,kGAAkG;YAClG,6GAA6G;YAC7G,iHAAiH;YACjH,MAAM,KAAK,GAAG;gBACZ,IAAI,EAAE,SAAS,CAAC,IAAI;gBACpB,QAAQ,EAAE,SAAS,CAAC,QAAQ;aAC7B,CAAA;YAED,MAAM,YAAY,GAAgC;gBAChD,GAAG,IAAI;gBACP,GAAG,SAAS,CAAC,OAAO;aACrB,CAAA;YAED,+EAA+E;YAC/E,0BAA0B;YAC1B,mCAAmC;YACnC,iDAAiD;YAEjD,IACE,YAAY,CAAC,QAAQ,IAAI,SAAS;gBAClC,CAAC,YAAY,CAAC,QAAQ,GAAG,CAAC;oBACxB,YAAY,CAAC,QAAQ,GAAG,qBAAa,CAAC,MAAM,CAAC,EAC/C,CAAC;gBACD,IAAI,CAAC,OAAO,CAAC,IAAI,CACf,2BAA2B,YAAY,CAAC,QAAQ,cAAc,SAAS,CAAC,IAAI,2BAA2B,qBAAa,CAAC,MAAM,EAAE,CAC9H,CAAA;gBACD,YAAY,CAAC,QAAQ,GAAG,qBAAa,CAAC,OAAO,CAAA;gBAC7C,IAAI,CAAC,OAAO,CAAC,IAAI,CACf,sCAAsC,qBAAa,CAAC,OAAO,cAAc,SAAS,CAAC,IAAI,EAAE,CAC1F,CAAA;YACH,CAAC;YAED,OAAO;gBACL,IAAI,EAAE,KAAK;gBACX,IAAI,EAAE,SAAS,CAAC,IAAI;gBACpB,IAAI,EAAE,YAAY;aACI,CAAA;QAC1B,CAAC,CAAC,CAAA;IACJ,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,IAAI,CACR,UAAqC,EACrC,UAAmB,EAAE;QAErB,IAAI,eAAe,GAAG,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAA;QAE3E,MAAM,EAAE,gBAAgB,GAAG,GAAG,EAAE,GAAG,OAAO,CAAA;QAC1C,OAAO,OAAO,CAAC,gBAAgB,CAAA;QAE/B,MAAM,YAAY,GAAG,eAAe,CAAC,MAAM,CACzC,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC,IAAA,iBAAS,EAAC,SAAS,CAAC,QAAQ,EAAE,YAAY,CAAC,CAC5D,CAAA;QAED,MAAM,aAAa,GAAG,eAAe,CAAC,MAAM,CAAC,CAAC,SAAS,EAAE,EAAE,CACzD,IAAA,iBAAS,EAAC,SAAS,CAAC,QAAQ,EAAE,YAAY,CAAC,CAC5C,CAAA;QAED,MAAM,cAAc,GAAG,IAAI,GAAG,EAAwB,CAAA;QAEtD,KAAK,MAAM,KAAK,IAAI,aAAa,EAAE,CAAC;YAClC,MAAM,OAAO,GAAG,KAAK,CAAC,QAAQ,EAAE,YAAa,CAAA;YAC7C,MAAM,WAAW,GAAG,cAAc,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,CAAA;YAErD,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;YACvB,cAAc,CAAC,GAAG,CAAC,OAAO,EAAE,WAAW,CAAC,CAAA;QAC1C,CAAC;QAED,MAAM,QAAQ,GAAuB,EAAE,CAAA;QAEvC,IAAI,YAAY,CAAC,MAAM,EAAE,CAAC;YACxB,YAAY,CAAC,GAAG,CAAC,CAAC,SAAS,EAAE,EAAE,CAC7B,IAAI,CAAC,gBAAgB,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC,CACvD,CAAA;YAED,MAAM,qBAAqB,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC,SAAS,EAAE,EAAE;gBAC9D,MAAM,gBAAgB,GACpB,IAAI,CAAC,qBAAqB,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,EAAE,CAAA;gBACtD,MAAM,mBAAmB,GAAG,IAAI,CAAC,qBAAqB,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,CAAA;gBACrE,OAAO,gBAAgB,CAAC,MAAM,IAAI,mBAAmB,CAAC,MAAM,CAAA;YAC9D,CAAC,CAAC,CAAA;YAEF,IAAI,qBAAqB,CAAC,MAAM,EAAE,CAAC;gBACjC,MAAM,QAAQ,GAAG,IAAI,CAAC,WAAW,CAAC,qBAAqB,EAAE,OAAO,CAAC,CAAA;gBACjE,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAA;YAC9C,CAAC;QACH,CAAC;QAED,KAAK,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,IAAI,cAAc,CAAC,OAAO,EAAE,EAAE,CAAC;YACzD,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC;gBACpB,SAAQ;YACV,CAAC;YAED,8DAA8D;YAC9D,mFAAmF;YACnF,qGAAqG;YACrG,iDAAiD;YACjD,KAAK,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,gBAAgB,CAAC,CAAA;YAE9C,MAAM,UAAU,GAAG,IAAI,CAAC,WAAW,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;YAEpD,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC,CAAA;QACtD,CAAC;QAED,MAAM,IAAA,kBAAU,EAAC,QAAQ,CAAC,CAAA;IAC5B,CAAC;IAEO,KAAK,CAAC,SAAS,CAAC,YAAoB,EAAE,GAAW;QACvD,IAAI,CAAC,YAAY,EAAE,CAAC;YAClB,OAAM;QACR,CAAC;QAED,MAAM,IAAI,CAAC,wBAAwB,CAAC,MAAM,CAAC,WAAW,YAAY,EAAE,EAAE,GAAG,CAAC,CAAA;IAC5E,CAAC;IAEO,KAAK,CAAC,WAAW,CACvB,YAAoB,EACpB,MAA6B;QAE7B,MAAM,IAAI,CAAC,wBAAwB,CAAC,KAAK,CACvC,WAAW,YAAY,EAAE,EACzB,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAChD,CAAA;IACH,CAAC;IAEO,KAAK,CAAC,gBAAgB,CAC5B,YAAoB;QAEpB,OAAO,MAAM,IAAI,CAAC,wBAAwB;aACvC,MAAM,CAAC,WAAW,YAAY,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;aACxC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE;YACf,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC,UAAU,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAA;QAC3D,CAAC,CAAC,CAAA;IACN,CAAC;IAED,KAAK,CAAC,oBAAoB,CAAC,YAAoB;QAC7C,MAAM,aAAa,GAAG,MAAM,IAAI,CAAC,gBAAgB,CAAC,YAAY,CAAC,CAAA;QAE/D,mDAAmD;QACnD,4DAA4D;QAC5D,aAAa,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE;YAC5B,MAAM,OAAO,GAAG;gBACd,IAAI,EAAE,OAAO,CAAC,IAAI;gBAClB,IAAI,EAAE,OAAO,CAAC,IAAI;gBAClB,QAAQ,EAAE,OAAO,CAAC,IAAI,CAAC,QAAQ;aAChC,CAAA;YACD,IAAI,CAAC,gBAAgB,CAAC,OAAc,EAAE;gBACpC,SAAS,EAAE,IAAI;gBACf,YAAY;aACb,CAAC,CAAA;QACJ,CAAC,CAAC,CAAA;QAEF,MAAM,qBAAqB,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE;YAC7D,MAAM,gBAAgB,GACpB,IAAI,CAAC,qBAAqB,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE,CAAA;YACpD,MAAM,mBAAmB,GAAG,IAAI,CAAC,qBAAqB,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,CAAA;YACrE,OAAO,gBAAgB,CAAC,MAAM,IAAI,mBAAmB,CAAC,MAAM,CAAA;QAC9D,CAAC,CAAC,CAAA;QAEF,IAAI,qBAAqB,CAAC,MAAM,EAAE,CAAC;YACjC,MAAM,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,qBAAqB,CAAC,CAAA;QAClD,CAAC;QAED,MAAM,IAAI,CAAC,kBAAkB,CAAC,YAAY,CAAC,CAAA;IAC7C,CAAC;IAED,KAAK,CAAC,kBAAkB,CACtB,YAAoB,EACpB,EACE,UAAU,MAGR,EAAE;QAEN,IAAI,CAAC,YAAY,EAAE,CAAC;YAClB,OAAM;QACR,CAAC;QAED,IAAI,UAAU,EAAE,MAAM,EAAE,CAAC;YACvB;;;eAGG;YAEH,MAAM,YAAY,GAAG,MAAM,IAAI,CAAC,wBAAwB;iBACrD,MAAM,CAAC,WAAW,YAAY,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;iBACxC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE;gBACf,OAAO,MAAM;qBACV,GAAG,CAAC,CAAC,UAAU,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;qBAC3C,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,UAAU,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAA;YACxD,CAAC,CAAC,CAAA;YAEJ,oBAAoB;YACpB,MAAM,QAAQ,GAAG,IAAI,CAAC,wBAAwB,CAAC,QAAQ,EAAE,CAAA;YAEzD,yBAAyB;YACzB,QAAQ,CAAC,GAAG,CAAC,WAAW,YAAY,EAAE,CAAC,CAAA;YAEvC,uCAAuC;YACvC,QAAQ,CAAC,KAAK,CACZ,WAAW,YAAY,EAAE,EACzB,GAAG,YAAY,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CACtD,CAAA;YAED,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAA;YAErB,OAAM;QACR,CAAC;QAED,MAAM,IAAI,CAAC,wBAAwB,CAAC,MAAM,CAAC,WAAW,YAAY,EAAE,CAAC,CAAA;IACvE,CAAC;CA8GF;AA1aD,uCA0aC"}
@@ -0,0 +1 @@
1
+ {"root":["../src/index.ts","../src/initialize/index.ts","../src/loaders/index.ts","../src/services/event-bus-redis.ts","../src/services/__tests__/event-bus.ts","../src/types/index.ts"],"version":"5.9.3"}
@@ -0,0 +1,62 @@
1
+ import { BulkJobOptions, Job, JobsOptions, QueueOptions, WorkerOptions } from "bullmq";
2
+ import { RedisOptions } from "ioredis";
3
+ export type JobData<T> = {
4
+ eventName: string;
5
+ data: T;
6
+ completedSubscriberIds?: string[] | undefined;
7
+ };
8
+ export type Options = BulkJobOptions & {
9
+ groupedEventsTTL?: number;
10
+ internal?: boolean;
11
+ };
12
+ export type BullJob<T> = {
13
+ data: JobData<T>;
14
+ opts: Job["opts"] & Options;
15
+ } & Job;
16
+ export type EmitOptions = JobsOptions;
17
+ export type EventBusRedisModuleOptions = {
18
+ /**
19
+ * Queue name for the event bus
20
+ */
21
+ queueName?: string;
22
+ /**
23
+ * Options for BullMQ Queue instance
24
+ * @see https://api.docs.bullmq.io/interfaces/v5.QueueOptions.html
25
+ */
26
+ queueOptions?: Omit<QueueOptions, "connection">;
27
+ /**
28
+ * Options for BullMQ Worker instance
29
+ * @see https://api.docs.bullmq.io/interfaces/v5.WorkerOptions.html
30
+ */
31
+ workerOptions?: Omit<WorkerOptions, "connection">;
32
+ /**
33
+ * Redis connection string
34
+ */
35
+ redisUrl?: string;
36
+ /**
37
+ * Redis client options
38
+ */
39
+ redisOptions?: RedisOptions;
40
+ /**
41
+ * Global options passed to all `EventBusService.emit` in the core as well as your own emitters. The options are forwarded to Bull's `Queue.add` method.
42
+ *
43
+ * The global options can be overridden by passing options to `EventBusService.emit` directly.
44
+ *
45
+ * Example
46
+ * ```js
47
+ * {
48
+ * removeOnComplete: { age: 10 },
49
+ * }
50
+ * ```
51
+ *
52
+ * @see https://api.docs.bullmq.io/interfaces/BaseJobOptions.html
53
+ */
54
+ jobOptions?: EmitOptions;
55
+ };
56
+ declare module "@acmekit/types" {
57
+ interface ModuleOptions {
58
+ "@acmekit/event-bus-redis": EventBusRedisModuleOptions;
59
+ "@acmekit/acmekit/event-bus-redis": EventBusRedisModuleOptions;
60
+ }
61
+ }
62
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAOA,OAAO,EACL,cAAc,EACd,GAAG,EACH,WAAW,EACX,YAAY,EACZ,aAAa,EACd,MAAM,QAAQ,CAAA;AACf,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AAEtC,MAAM,MAAM,OAAO,CAAC,CAAC,IAAI;IACvB,SAAS,EAAE,MAAM,CAAA;IACjB,IAAI,EAAE,CAAC,CAAA;IACP,sBAAsB,CAAC,EAAE,MAAM,EAAE,GAAG,SAAS,CAAA;CAC9C,CAAA;AAED,MAAM,MAAM,OAAO,GAAG,cAAc,GAAG;IACrC,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB,CAAA;AAED,MAAM,MAAM,OAAO,CAAC,CAAC,IAAI;IACvB,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,CAAA;IAChB,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,OAAO,CAAA;CAC5B,GAAG,GAAG,CAAA;AAEP,MAAM,MAAM,WAAW,GAAG,WAAW,CAAA;AAErC,MAAM,MAAM,0BAA0B,GAAG;IACvC;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;IAElB;;;OAGG;IACH,YAAY,CAAC,EAAE,IAAI,CAAC,YAAY,EAAE,YAAY,CAAC,CAAA;IAE/C;;;OAGG;IACH,aAAa,CAAC,EAAE,IAAI,CAAC,aAAa,EAAE,YAAY,CAAC,CAAA;IAEjD;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;IAEjB;;OAEG;IACH,YAAY,CAAC,EAAE,YAAY,CAAA;IAE3B;;;;;;;;;;;;;OAaG;IACH,UAAU,CAAC,EAAE,WAAW,CAAA;CAGzB,CAAA;AAED,OAAO,QAAQ,gBAAgB,CAAC;IAC9B,UAAU,aAAa;QACrB,0BAA0B,EAAE,0BAA0B,CAAA;QACtD,kCAAkC,EAAE,0BAA0B,CAAA;KAC/D;CACF"}
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ // TODO: Comment temporarely and we will re enable it in the near future #14478
3
+ // import type { EventBusEventsOptions } from "@acmekit/types"
4
+ Object.defineProperty(exports, "__esModule", { value: true });
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":";AAAA,+EAA+E;AAC/E,8DAA8D"}
package/package.json ADDED
@@ -0,0 +1,43 @@
1
+ {
2
+ "name": "@acmekit/event-bus-redis",
3
+ "version": "2.13.1",
4
+ "description": "Redis Event Bus Module for AcmeKit",
5
+ "main": "dist/index.js",
6
+ "files": [
7
+ "dist",
8
+ "!dist/**/__tests__",
9
+ "!dist/**/__mocks__",
10
+ "!dist/**/__fixtures__"
11
+ ],
12
+ "repository": {
13
+ "type": "git",
14
+ "url": "https://github.com/acmekit/acmekit",
15
+ "directory": "packages/modules/event-bus-redis"
16
+ },
17
+ "publishConfig": {
18
+ "access": "public"
19
+ },
20
+ "engines": {
21
+ "node": ">=20"
22
+ },
23
+ "author": "AcmeKit",
24
+ "license": "MIT",
25
+ "devDependencies": {
26
+ "@acmekit/framework": "2.13.1",
27
+ "@acmekit/types": "2.13.1",
28
+ "@acmekit/utils": "2.13.1"
29
+ },
30
+ "scripts": {
31
+ "watch": "yarn run -T tsc --build --watch",
32
+ "build": "yarn run -T rimraf dist && yarn run -T tsc --build",
33
+ "test": "../../../node_modules/.bin/jest --silent --bail --forceExit",
34
+ "test:integration": "../../../node_modules/.bin/jest --passWithNoTests --no-cache --bail --detectOpenHandles --forceExit --logHeapUsage --testPathPattern=\"integration-tests/__tests__/.*\\.spec\\.ts\""
35
+ },
36
+ "dependencies": {
37
+ "bullmq": "5.13.0",
38
+ "ioredis": "^5.4.1"
39
+ },
40
+ "peerDependencies": {
41
+ "@acmekit/framework": "2.13.1"
42
+ }
43
+ }