diff --git a/apps/expiration/src/app/orders/orders.module.ts b/apps/expiration/src/app/orders/orders.module.ts index 9ffc70f8..23b411ad 100644 --- a/apps/expiration/src/app/orders/orders.module.ts +++ b/apps/expiration/src/app/orders/orders.module.ts @@ -10,6 +10,7 @@ import { type AmqpOptions, AmqpClient, } from '@s1seven/nestjs-tools-amqp-transport'; +import { getReplyQueueName } from '@ticketing/microservices/shared/rmq'; import { Services } from '@ticketing/shared/constants'; import { AppConfigService } from '../env'; @@ -40,7 +41,10 @@ import { OrdersMSController } from './orders-ms.controller'; exclusive: false, autoDelete: false, }, - replyQueue: `${Services.ORDERS_SERVICE}_REPLY_${Services.EXPIRATION_SERVICE}_QUEUE`, + replyQueue: getReplyQueueName( + Services.ORDERS_SERVICE, + Services.EXPIRATION_SERVICE, + ), replyQueueOptions: { durable: true, exclusive: true, diff --git a/apps/orders/src/app/orders/orders.module.ts b/apps/orders/src/app/orders/orders.module.ts index 0b26b35f..53e2ab8e 100644 --- a/apps/orders/src/app/orders/orders.module.ts +++ b/apps/orders/src/app/orders/orders.module.ts @@ -11,6 +11,7 @@ import { OryModule } from '@ticketing/microservices/ory-client'; import { PassportModule } from '@ticketing/microservices/shared/fastify-passport'; import { GlobalErrorFilter } from '@ticketing/microservices/shared/filters'; import { JwtStrategy } from '@ticketing/microservices/shared/guards'; +import { getReplyQueueName } from '@ticketing/microservices/shared/rmq'; import { CURRENT_USER_KEY, Services } from '@ticketing/shared/constants'; import { AppConfigService } from '../env'; @@ -35,7 +36,7 @@ const clientFactory = ( prefetchCount: configService.get('RMQ_PREFETCH_COUNT'), isGlobalPrefetchCount: false, queue: `${consumerService}_QUEUE`, - replyQueue: `${consumerService}_REPLY_${Services.TICKETS_SERVICE}_QUEUE`, + replyQueue: getReplyQueueName(consumerService, Services.TICKETS_SERVICE), queueOptions: { durable: true, exclusive: false, diff --git a/apps/orders/test/tickets-ms.e2e-spec.ts b/apps/orders/test/tickets-ms.e2e-spec.ts index 63cdf86b..0d509db3 100644 --- a/apps/orders/test/tickets-ms.e2e-spec.ts +++ b/apps/orders/test/tickets-ms.e2e-spec.ts @@ -13,6 +13,7 @@ import { AmqpClient, AmqpServer } from '@s1seven/nestjs-tools-amqp-transport'; import { loadEnv, validate } from '@ticketing/microservices/shared/env'; import { Patterns } from '@ticketing/microservices/shared/events'; import { GlobalErrorFilter } from '@ticketing/microservices/shared/filters'; +import { getReplyQueueName } from '@ticketing/microservices/shared/rmq'; import { Services } from '@ticketing/shared/constants'; import { Model, Types } from 'mongoose'; import { delay, lastValueFrom } from 'rxjs'; @@ -63,7 +64,10 @@ describe('TicketsMSController (e2e)', () => { prefetchCount: 1, isGlobalPrefetchCount: false, queue: `${Services.ORDERS_SERVICE}_QUEUE`, - replyQueue: `${Services.ORDERS_SERVICE}_REPLY_${Services.TICKETS_SERVICE}_QUEUE`, + replyQueue: getReplyQueueName( + Services.ORDERS_SERVICE, + Services.TICKETS_SERVICE, + ), queueOptions: { durable: false, exclusive: false, diff --git a/apps/payments/src/app/payments/payments.module.ts b/apps/payments/src/app/payments/payments.module.ts index 7112681c..4dfe357c 100644 --- a/apps/payments/src/app/payments/payments.module.ts +++ b/apps/payments/src/app/payments/payments.module.ts @@ -12,6 +12,7 @@ import { OryModule } from '@ticketing/microservices/ory-client'; import { PassportModule } from '@ticketing/microservices/shared/fastify-passport'; import { GlobalErrorFilter } from '@ticketing/microservices/shared/filters'; import { JwtStrategy } from '@ticketing/microservices/shared/guards'; +import { getReplyQueueName } from '@ticketing/microservices/shared/rmq'; import { CURRENT_USER_KEY, Services } from '@ticketing/shared/constants'; import { updateIfCurrentPlugin } from 'mongoose-update-if-current'; @@ -61,7 +62,10 @@ const MongooseFeatures = MongooseModule.forFeatureAsync([ prefetchCount: configService.get('RMQ_PREFETCH_COUNT'), isGlobalPrefetchCount: false, queue: `${Services.ORDERS_SERVICE}_QUEUE`, - replyQueue: `${Services.ORDERS_SERVICE}_REPLY_${Services.PAYMENTS_SERVICE}_QUEUE`, + replyQueue: getReplyQueueName( + Services.ORDERS_SERVICE, + Services.PAYMENTS_SERVICE, + ), queueOptions: { durable: true, exclusive: false, diff --git a/apps/tickets/src/app/tickets/tickets.module.ts b/apps/tickets/src/app/tickets/tickets.module.ts index 104b4557..b9bb6a9c 100644 --- a/apps/tickets/src/app/tickets/tickets.module.ts +++ b/apps/tickets/src/app/tickets/tickets.module.ts @@ -12,6 +12,7 @@ import { OryModule } from '@ticketing/microservices/ory-client'; import { PassportModule } from '@ticketing/microservices/shared/fastify-passport'; import { GlobalErrorFilter } from '@ticketing/microservices/shared/filters'; import { JwtStrategy } from '@ticketing/microservices/shared/guards'; +import { getReplyQueueName } from '@ticketing/microservices/shared/rmq'; import { CURRENT_USER_KEY, Services } from '@ticketing/shared/constants'; import { updateIfCurrentPlugin } from 'mongoose-update-if-current'; @@ -45,7 +46,10 @@ const OrdersClient = ClientsModule.registerAsync([ prefetchCount: configService.get('RMQ_PREFETCH_COUNT'), isGlobalPrefetchCount: false, queue: `${Services.ORDERS_SERVICE}_QUEUE`, - replyQueue: `${Services.ORDERS_SERVICE}_REPLY_${Services.TICKETS_SERVICE}_QUEUE`, + replyQueue: getReplyQueueName( + Services.ORDERS_SERVICE, + Services.TICKETS_SERVICE, + ), queueOptions: { durable: true, exclusive: false, diff --git a/apps/tickets/test/orders-ms.e2e-spec.ts b/apps/tickets/test/orders-ms.e2e-spec.ts index 0ab6a892..b79fbd06 100644 --- a/apps/tickets/test/orders-ms.e2e-spec.ts +++ b/apps/tickets/test/orders-ms.e2e-spec.ts @@ -13,6 +13,7 @@ import { AmqpClient, AmqpServer } from '@s1seven/nestjs-tools-amqp-transport'; import { loadEnv, validate } from '@ticketing/microservices/shared/env'; import { Patterns } from '@ticketing/microservices/shared/events'; import { GlobalErrorFilter } from '@ticketing/microservices/shared/filters'; +import { getReplyQueueName } from '@ticketing/microservices/shared/rmq'; import { Services } from '@ticketing/shared/constants'; import { Types } from 'mongoose'; import { delay, lastValueFrom } from 'rxjs'; @@ -60,7 +61,10 @@ describe('OrdersMSController (e2e)', () => { prefetchCount: 1, isGlobalPrefetchCount: false, queue: `${Services.TICKETS_SERVICE}_QUEUE`, - replyQueue: `${Services.TICKETS_SERVICE}_REPLY_${Services.TICKETS_SERVICE}_QUEUE`, + replyQueue: getReplyQueueName( + Services.TICKETS_SERVICE, + Services.ORDERS_SERVICE, + ), queueOptions: { durable: false, exclusive: false, diff --git a/libs/microservices/shared/nats-streaming/.babelrc b/libs/microservices/shared/nats-streaming/.babelrc deleted file mode 100644 index cf7ddd99..00000000 --- a/libs/microservices/shared/nats-streaming/.babelrc +++ /dev/null @@ -1,3 +0,0 @@ -{ - "presets": [["@nrwl/web/babel", { "useBuiltIns": "usage" }]] -} diff --git a/libs/microservices/shared/nats-streaming/README.md b/libs/microservices/shared/nats-streaming/README.md deleted file mode 100644 index 738f540a..00000000 --- a/libs/microservices/shared/nats-streaming/README.md +++ /dev/null @@ -1,7 +0,0 @@ -# microservices-shared-nats-streaming - -This library was generated with [Nx](https://nx.dev). - -## Running unit tests - -Run `nx test microservices-shared-nats-streaming` to execute the unit tests via [Jest](https://jestjs.io). diff --git a/libs/microservices/shared/nats-streaming/jest.config.ts b/libs/microservices/shared/nats-streaming/jest.config.ts deleted file mode 100644 index 14539921..00000000 --- a/libs/microservices/shared/nats-streaming/jest.config.ts +++ /dev/null @@ -1,17 +0,0 @@ -export default { - displayName: 'microservices-shared-nats-streaming', - - globals: { - 'ts-jest': { - tsconfig: '/tsconfig.spec.json', - }, - }, - testEnvironment: 'node', - transform: { - '^.+\\.[tj]sx?$': 'ts-jest', - }, - moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'], - coverageDirectory: - '../../../../coverage/libs/microservices/shared/nats-streaming', - preset: '../../../../jest.preset.js', -}; diff --git a/libs/microservices/shared/nats-streaming/project.json b/libs/microservices/shared/nats-streaming/project.json deleted file mode 100644 index d42f975c..00000000 --- a/libs/microservices/shared/nats-streaming/project.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "name": "microservices-shared-nats-streaming", - "$schema": "../../../../node_modules/nx/schemas/project-schema.json", - "sourceRoot": "libs/microservices/shared/nats-streaming/src", - "projectType": "library", - "targets": { - "lint": { - "executor": "@nx/eslint:lint", - "outputs": ["{options.outputFile}"], - "options": { - "lintFilePatterns": ["libs/microservices/shared/nats-streaming/**/*.ts"] - } - }, - "test": { - "executor": "@nx/jest:jest", - "outputs": [ - "{workspaceRoot}/coverage/libs/microservices/shared/nats-streaming" - ], - "options": { - "jestConfig": "libs/microservices/shared/nats-streaming/jest.config.ts", - "passWithNoTests": true - } - } - }, - "tags": ["scope:shared", "type:utils", "platform:server"] -} diff --git a/libs/microservices/shared/nats-streaming/src/index.ts b/libs/microservices/shared/nats-streaming/src/index.ts deleted file mode 100644 index 0dd6502e..00000000 --- a/libs/microservices/shared/nats-streaming/src/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export * from './nats-streaming.config'; -export * from './nats-streaming.healthcheck'; -export * from './nats-streaming.publisher'; diff --git a/libs/microservices/shared/nats-streaming/src/nats-streaming.config.ts b/libs/microservices/shared/nats-streaming/src/nats-streaming.config.ts deleted file mode 100644 index 995a8ae1..00000000 --- a/libs/microservices/shared/nats-streaming/src/nats-streaming.config.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { ConfigService } from '@nestjs/config'; -import { NatsStreamingPublishOptions } from '@nestjs-plugins/nestjs-nats-streaming-transport'; -import { - BaseEnvironmentVariables, - NatsEnvironmentVariables, -} from '@ticketing/microservices/shared/env'; - -export class NatsStreamingConfig< - T extends NatsEnvironmentVariables & BaseEnvironmentVariables -> { - constructor( - private readonly configService: ConfigService, - private readonly extraOptions: Partial = {} - ) {} - - get url(): string { - return this.configService.get('NATS_URL'); - } - - get options(): NatsStreamingPublishOptions { - const configService = this.configService; - const baseOptions: NatsStreamingPublishOptions = { - clientId: configService.get('NATS_CLIENT_ID'), - clusterId: configService.get('NATS_CLUSTER_ID'), - connectOptions: { - url: configService.get('NATS_URL'), - ...(this.extraOptions?.connectOptions || {}), - }, - }; - return { ...baseOptions, ...this.extraOptions }; - } -} diff --git a/libs/microservices/shared/nats-streaming/src/nats-streaming.healthcheck.ts b/libs/microservices/shared/nats-streaming/src/nats-streaming.healthcheck.ts deleted file mode 100644 index 8ce49386..00000000 --- a/libs/microservices/shared/nats-streaming/src/nats-streaming.healthcheck.ts +++ /dev/null @@ -1,95 +0,0 @@ -import { Injectable } from '@nestjs/common'; -import { - HealthCheckError, - HealthIndicator, - HealthIndicatorResult, - TimeoutError, -} from '@nestjs/terminus'; -import { NatsStreamingPublishOptions } from '@nestjs-plugins/nestjs-nats-streaming-transport'; - -import { NatsStreamingPublisher } from './nats-streaming.publisher'; - -export interface NatsStreamingHealthCheckOptions { - options?: NatsStreamingPublishOptions; - timeout?: number; -} - -export class NatsStreamingHealthCheckTimeoutError extends Error { - constructor(message: string) { - super(message); - this.name = this.constructor.name; - Object.setPrototypeOf(this, NatsStreamingHealthCheckTimeoutError.prototype); - Error.captureStackTrace(this, this.constructor); - } -} - -// @Injectable({ scope: Scope.TRANSIENT }) -@Injectable() -export class NatsStreamingHealthCheck extends HealthIndicator { - constructor() { - super(); - } - - promiseTimeout(delay = 1000, fn: Promise): Promise { - return new Promise((resolve, reject) => { - const timeout = setTimeout( - () => - reject( - new NatsStreamingHealthCheckTimeoutError( - 'NATS Streaming connection timed out' - ) - ), - delay - ); - fn.then(() => resolve()) - .catch((e) => reject(e)) - .finally(() => clearTimeout(timeout)); - }); - } - - private async pingMicroservice( - options: NatsStreamingHealthCheckOptions - ): Promise { - const client = new NatsStreamingPublisher(options.options); - const checkConnection = async (): Promise => { - await client.connect(); - client.close(); - }; - return await checkConnection(); - } - - async pingCheck( - key: string, - options: NatsStreamingHealthCheckOptions - ): Promise { - let isHealthy = false; - const timeout = options.timeout || 1000; - try { - await this.promiseTimeout(timeout, this.pingMicroservice(options)); - isHealthy = true; - } catch (err) { - this.generateError(key, err, timeout); - } - return this.getStatus(key, isHealthy); - } - - private generateError(key: string, error: Error, timeout: number): void { - if (!error) { - return; - } - if (error instanceof NatsStreamingHealthCheckTimeoutError) { - throw new TimeoutError( - timeout, - this.getStatus(key, false, { - message: `timeout of ${timeout}ms exceeded`, - }) - ); - } - throw new HealthCheckError( - error.message, - this.getStatus(key, false, { - message: error.message, - }) - ); - } -} diff --git a/libs/microservices/shared/nats-streaming/src/nats-streaming.publisher.ts b/libs/microservices/shared/nats-streaming/src/nats-streaming.publisher.ts deleted file mode 100644 index 2f13d9fb..00000000 --- a/libs/microservices/shared/nats-streaming/src/nats-streaming.publisher.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { randomBytes } from 'node:crypto'; -import * as nats from 'node-nats-streaming'; - -export class NatsStreamingPublisher { - connection: nats.Stan; - - constructor( - private options: { - clusterId: string; - clientId: string; - connectOptions?: nats.StanOptions; - } - ) {} - - createConnection( - clusterID: string, - clientID: string, - connectOptions?: nats.StanOptions - ): Promise { - const nc = nats.connect( - clusterID, - `${clientID}-${randomBytes(8).toString('hex')}`, - connectOptions - ); - return new Promise((resolve, reject) => { - nc.on('connect', () => resolve(nc)); - nc.on('error', (err) => reject(err)); - }); - } - - async connect(): Promise { - if (this.connection) { - return Promise.resolve(this.connection); - } - this.connection = await this.createConnection( - this.options.clusterId, - this.options.clientId, - this.options.connectOptions - ); - return this.connection; - } - - close(): void { - this.connection.close(); - this.connection = null; - } -} diff --git a/libs/microservices/shared/nats-streaming/tsconfig.json b/libs/microservices/shared/nats-streaming/tsconfig.json deleted file mode 100644 index 26b7b4af..00000000 --- a/libs/microservices/shared/nats-streaming/tsconfig.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "extends": "../../../../tsconfig.base.json", - "files": [], - "include": [], - "references": [ - { - "path": "./tsconfig.lib.json" - }, - { - "path": "./tsconfig.spec.json" - } - ] -} diff --git a/libs/microservices/shared/nats-streaming/tsconfig.lib.json b/libs/microservices/shared/nats-streaming/tsconfig.lib.json deleted file mode 100644 index 8ad4d984..00000000 --- a/libs/microservices/shared/nats-streaming/tsconfig.lib.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "extends": "./tsconfig.json", - "compilerOptions": { - "module": "commonjs", - "outDir": "../../../../dist/out-tsc", - "declaration": true, - "types": ["node"] - }, - "exclude": ["**/*.spec.ts", "jest.config.ts"], - "include": ["**/*.ts"] -} diff --git a/libs/microservices/shared/nats-streaming/.eslintrc.json b/libs/microservices/shared/rmq/.eslintrc.json similarity index 100% rename from libs/microservices/shared/nats-streaming/.eslintrc.json rename to libs/microservices/shared/rmq/.eslintrc.json diff --git a/libs/microservices/shared/rmq/README.md b/libs/microservices/shared/rmq/README.md new file mode 100644 index 00000000..bf044576 --- /dev/null +++ b/libs/microservices/shared/rmq/README.md @@ -0,0 +1,7 @@ +# microservices-shared-rmq + +This library was generated with [Nx](https://nx.dev). + +## Running unit tests + +Run `nx test microservices-shared-rmq` to execute the unit tests via [Jest](https://jestjs.io). diff --git a/libs/microservices/shared/rmq/jest.config.ts b/libs/microservices/shared/rmq/jest.config.ts new file mode 100644 index 00000000..b985ef13 --- /dev/null +++ b/libs/microservices/shared/rmq/jest.config.ts @@ -0,0 +1,11 @@ +/* eslint-disable */ +export default { + displayName: 'microservices-shared-rmq', + preset: '../../../../jest.preset.js', + testEnvironment: 'node', + transform: { + '^.+\\.[tj]s$': ['ts-jest', { tsconfig: '/tsconfig.spec.json' }], + }, + moduleFileExtensions: ['ts', 'js', 'html'], + coverageDirectory: '../../../../coverage/libs/microservices/shared/rmq', +}; diff --git a/libs/microservices/shared/rmq/project.json b/libs/microservices/shared/rmq/project.json new file mode 100644 index 00000000..af33e6ef --- /dev/null +++ b/libs/microservices/shared/rmq/project.json @@ -0,0 +1,23 @@ +{ + "name": "microservices-shared-rmq", + "$schema": "../../../../node_modules/nx/schemas/project-schema.json", + "sourceRoot": "libs/microservices/shared/rmq/src", + "projectType": "library", + "targets": { + "lint": { + "executor": "@nx/eslint:lint", + "outputs": ["{options.outputFile}"], + "options": { + "lintFilePatterns": ["libs/microservices/shared/rmq/**/*.ts"] + } + }, + "test": { + "executor": "@nx/jest:jest", + "outputs": ["{workspaceRoot}/coverage/{projectRoot}"], + "options": { + "jestConfig": "libs/microservices/shared/rmq/jest.config.ts" + } + } + }, + "tags": ["scope:shared", "type:utils", "platform:server"] +} diff --git a/libs/microservices/shared/rmq/src/index.ts b/libs/microservices/shared/rmq/src/index.ts new file mode 100644 index 00000000..9c731693 --- /dev/null +++ b/libs/microservices/shared/rmq/src/index.ts @@ -0,0 +1 @@ +export * from './lib/helpers'; diff --git a/libs/microservices/shared/rmq/src/lib/helpers.ts b/libs/microservices/shared/rmq/src/lib/helpers.ts new file mode 100644 index 00000000..6ead4010 --- /dev/null +++ b/libs/microservices/shared/rmq/src/lib/helpers.ts @@ -0,0 +1,21 @@ +import { Services } from '@ticketing/shared/constants'; + +export type ProducerService = Services | 'SELF'; + +/** + * @description this function is used to get a unique reply queue name in combination with the exclusive option set to true. + * It's useful to avoid queue name collision between workers (or dynos in Heroku) of the same service while keeping a meaningful name. + * The pattern is: {consumerServiceName}_REPLY_{producerServiceName}_{randomSuffix} or {consumerServiceName}_REPLY_{producerServiceName}_{workerId}_{randomSuffix}. + */ +export function getReplyQueueName( + consumerServiceName: Services, + producerServiceName: ProducerService, + workerId?: number, +): string { + const baseQueueName = `${consumerServiceName}_REPLY_${producerServiceName}_QUEUE`; + // pseudo random suffix is enough to avoid queue name collision + const randomSuffix = Math.random().toString(36).substring(2, 15); + return workerId + ? `${baseQueueName}_${workerId}-${randomSuffix}` + : `${baseQueueName}_${randomSuffix}`; +} diff --git a/libs/microservices/shared/rmq/tsconfig.json b/libs/microservices/shared/rmq/tsconfig.json new file mode 100644 index 00000000..4022fd4d --- /dev/null +++ b/libs/microservices/shared/rmq/tsconfig.json @@ -0,0 +1,22 @@ +{ + "extends": "../../../../tsconfig.base.json", + "compilerOptions": { + "module": "commonjs", + "forceConsistentCasingInFileNames": true, + "strict": true, + "noImplicitOverride": true, + "noPropertyAccessFromIndexSignature": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true + }, + "files": [], + "include": [], + "references": [ + { + "path": "./tsconfig.lib.json" + }, + { + "path": "./tsconfig.spec.json" + } + ] +} diff --git a/libs/microservices/shared/rmq/tsconfig.lib.json b/libs/microservices/shared/rmq/tsconfig.lib.json new file mode 100644 index 00000000..23541c4e --- /dev/null +++ b/libs/microservices/shared/rmq/tsconfig.lib.json @@ -0,0 +1,15 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../../../dist/out-tsc", + "declaration": true, + "types": ["node"], + "strictNullChecks": true, + "noImplicitAny": true, + "strictBindCallApply": true, + "forceConsistentCasingInFileNames": true, + "noFallthroughCasesInSwitch": true + }, + "include": ["src/**/*.ts"], + "exclude": ["jest.config.ts", "src/**/*.spec.ts", "src/**/*.test.ts"] +} diff --git a/libs/microservices/shared/nats-streaming/tsconfig.spec.json b/libs/microservices/shared/rmq/tsconfig.spec.json similarity index 60% rename from libs/microservices/shared/nats-streaming/tsconfig.spec.json rename to libs/microservices/shared/rmq/tsconfig.spec.json index e83ff97c..6668655f 100644 --- a/libs/microservices/shared/nats-streaming/tsconfig.spec.json +++ b/libs/microservices/shared/rmq/tsconfig.spec.json @@ -6,11 +6,9 @@ "types": ["jest", "node"] }, "include": [ - "**/*.spec.ts", - "**/*.spec.tsx", - "**/*.spec.js", - "**/*.spec.jsx", - "**/*.d.ts", - "jest.config.ts" + "jest.config.ts", + "src/**/*.test.ts", + "src/**/*.spec.ts", + "src/**/*.d.ts" ] } diff --git a/tsconfig.base.json b/tsconfig.base.json index 1a791b42..9dcf4850 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -45,15 +45,15 @@ "@ticketing/microservices/shared/models": [ "libs/microservices/shared/models/src/index.ts" ], - "@ticketing/microservices/shared/nats-streaming": [ - "libs/microservices/shared/nats-streaming/src/index.ts" - ], "@ticketing/microservices/shared/pipes": [ "libs/microservices/shared/pipes/src/index.ts" ], "@ticketing/microservices/shared/redis": [ "libs/microservices/shared/redis/src/index.ts" ], + "@ticketing/microservices/shared/rmq": [ + "libs/microservices/shared/rmq/src/index.ts" + ], "@ticketing/microservices/shared/testing": [ "libs/microservices/shared/testing/src/index.ts" ],