@solidxai/core 0.1.9-beta.5 → 0.1.9-beta.6

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 (68) hide show
  1. package/dist/helpers/bootstrap.helper.d.ts.map +1 -1
  2. package/dist/helpers/bootstrap.helper.js +4 -1
  3. package/dist/helpers/bootstrap.helper.js.map +1 -1
  4. package/dist/interfaces/mq.d.ts +1 -1
  5. package/dist/interfaces/mq.d.ts.map +1 -1
  6. package/dist/interfaces/mq.js.map +1 -1
  7. package/dist/jobs/database/api-email-subscriber-database.service.d.ts +1 -1
  8. package/dist/jobs/database/api-email-subscriber-database.service.js +1 -1
  9. package/dist/jobs/database/api-email-subscriber-database.service.js.map +1 -1
  10. package/dist/jobs/database/msg91-whatsapp-subscriber-database.service.d.ts +1 -1
  11. package/dist/jobs/database/msg91-whatsapp-subscriber-database.service.js +1 -1
  12. package/dist/jobs/database/msg91-whatsapp-subscriber-database.service.js.map +1 -1
  13. package/dist/jobs/database/three60-whatsapp-subscriber-database.service.d.ts +1 -1
  14. package/dist/jobs/database/three60-whatsapp-subscriber-database.service.js +1 -1
  15. package/dist/jobs/database/three60-whatsapp-subscriber-database.service.js.map +1 -1
  16. package/dist/jobs/rabbitmq/api-email-subscriber.service.d.ts +1 -1
  17. package/dist/jobs/rabbitmq/api-email-subscriber.service.js +1 -1
  18. package/dist/jobs/rabbitmq/api-email-subscriber.service.js.map +1 -1
  19. package/dist/jobs/rabbitmq/msg91-whatsapp-subscriber.service.d.ts +1 -1
  20. package/dist/jobs/rabbitmq/msg91-whatsapp-subscriber.service.js +1 -1
  21. package/dist/jobs/rabbitmq/msg91-whatsapp-subscriber.service.js.map +1 -1
  22. package/dist/jobs/rabbitmq/test-queue-subscriber.service.d.ts +1 -1
  23. package/dist/jobs/rabbitmq/test-queue-subscriber.service.d.ts.map +1 -1
  24. package/dist/jobs/rabbitmq/test-queue-subscriber.service.js +6 -3
  25. package/dist/jobs/rabbitmq/test-queue-subscriber.service.js.map +1 -1
  26. package/dist/jobs/rabbitmq/three60-whatsapp-subscriber.service.d.ts +1 -1
  27. package/dist/jobs/rabbitmq/three60-whatsapp-subscriber.service.js +1 -1
  28. package/dist/jobs/rabbitmq/three60-whatsapp-subscriber.service.js.map +1 -1
  29. package/dist/jobs/redis/api-email-subscriber-redis.service.d.ts +1 -1
  30. package/dist/jobs/redis/api-email-subscriber-redis.service.js +1 -1
  31. package/dist/jobs/redis/api-email-subscriber-redis.service.js.map +1 -1
  32. package/dist/jobs/redis/msg91-whatsapp-subscriber-redis.service.d.ts +1 -1
  33. package/dist/jobs/redis/msg91-whatsapp-subscriber-redis.service.js +1 -1
  34. package/dist/jobs/redis/msg91-whatsapp-subscriber-redis.service.js.map +1 -1
  35. package/dist/jobs/redis/three60-whatsapp-subscriber-redis.service.d.ts +1 -1
  36. package/dist/jobs/redis/three60-whatsapp-subscriber-redis.service.js +1 -1
  37. package/dist/jobs/redis/three60-whatsapp-subscriber-redis.service.js.map +1 -1
  38. package/dist/seeders/seed-data/solid-core-metadata.json +7 -3
  39. package/dist/services/queues/database-subscriber.service.d.ts +1 -1
  40. package/dist/services/queues/database-subscriber.service.d.ts.map +1 -1
  41. package/dist/services/queues/database-subscriber.service.js.map +1 -1
  42. package/dist/services/queues/rabbitmq-subscriber.service.d.ts +1 -1
  43. package/dist/services/queues/rabbitmq-subscriber.service.d.ts.map +1 -1
  44. package/dist/services/queues/rabbitmq-subscriber.service.js +3 -1
  45. package/dist/services/queues/rabbitmq-subscriber.service.js.map +1 -1
  46. package/dist/services/queues/redis-subscriber.service.d.ts +1 -1
  47. package/dist/services/queues/redis-subscriber.service.d.ts.map +1 -1
  48. package/dist/services/queues/redis-subscriber.service.js.map +1 -1
  49. package/dist/winston.logger.js +1 -1
  50. package/dist/winston.logger.js.map +1 -1
  51. package/package.json +1 -1
  52. package/src/helpers/bootstrap.helper.ts +5 -2
  53. package/src/interfaces/mq.ts +2 -2
  54. package/src/jobs/database/api-email-subscriber-database.service.ts +1 -1
  55. package/src/jobs/database/msg91-whatsapp-subscriber-database.service.ts +1 -1
  56. package/src/jobs/database/three60-whatsapp-subscriber-database.service.ts +1 -1
  57. package/src/jobs/rabbitmq/api-email-subscriber.service.ts +1 -1
  58. package/src/jobs/rabbitmq/msg91-whatsapp-subscriber.service.ts +1 -1
  59. package/src/jobs/rabbitmq/test-queue-subscriber.service.ts +6 -7
  60. package/src/jobs/rabbitmq/three60-whatsapp-subscriber.service.ts +1 -1
  61. package/src/jobs/redis/api-email-subscriber-redis.service.ts +1 -1
  62. package/src/jobs/redis/msg91-whatsapp-subscriber-redis.service.ts +1 -1
  63. package/src/jobs/redis/three60-whatsapp-subscriber-redis.service.ts +1 -1
  64. package/src/seeders/seed-data/solid-core-metadata.json +7 -3
  65. package/src/services/queues/database-subscriber.service.ts +1 -1
  66. package/src/services/queues/rabbitmq-subscriber.service.ts +13 -11
  67. package/src/services/queues/redis-subscriber.service.ts +2 -2
  68. package/src/winston.logger.ts +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"database-subscriber.service.js","sourceRoot":"","sources":["../../../src/services/queues/database-subscriber.service.ts"],"names":[],"mappings":"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","sourcesContent":["import { Logger, OnModuleInit } from '@nestjs/common';\nimport { QueuesModuleOptions } from \"../../interfaces\";\nimport { QueueMessage, QueueSubscriber } from '../../interfaces/mq';\nimport { MqMessageQueueService } from '../mq-message-queue.service';\nimport { MqMessageService } from '../mq-message.service';\nimport { PollerService } from '../poller.service';\nimport { buildNamespacedQueueName } from './common';\n\nexport abstract class DatabaseSubscriber<T> implements OnModuleInit, QueueSubscriber<T> {\n private _loggerInstance?: Logger;\n private readonly url: string;\n private readonly serviceRole: string;\n\n constructor(\n protected readonly mqMessageService: MqMessageService,\n protected readonly mqMessageQueueService: MqMessageQueueService,\n protected readonly poller: PollerService,\n ) {\n this.serviceRole = process.env.QUEUES_SERVICE_ROLE;\n if (!this.serviceRole) {\n this.logger.debug('Queue service Role is not defined in the environment variables');\n }\n // this.logger.debug(`DatabaseSubscriber instance created with options: ${JSON.stringify(this.options())}`);\n }\n\n protected get loggerContext(): string {\n return this.constructor.name;\n }\n\n protected get logger(): Logger {\n if (!this._loggerInstance) {\n this._loggerInstance = new Logger(this.loggerContext);\n }\n return this._loggerInstance;\n }\n\n abstract subscribe(message: QueueMessage<T>);\n\n abstract options(): QueuesModuleOptions;\n\n private async processNext(queueName: string) {\n // this.logger.debug(`#### DatabaseSubscriber processing next message from queue: ${queueName}`);\n const job = await this.mqMessageService.lockNextPendingMessage(queueName);\n if (!job) {\n return;\n }\n\n const messageContentString = job.input.toString();\n // this.logger.debug(`DatabaseSubscriber Received raw message: ${messageContentString}`);\n\n let message: QueueMessage<T> = null;\n\n try {\n message = JSON.parse(messageContentString) as QueueMessage<T>;\n\n // this is the first time we are receiving the message so we set the currentRetry to 0\n if (!message.retryCount) message.retryCount = 0;\n if (!message.retryInterval) message.retryInterval = 1000;\n if (!message.currentRetry) message.currentRetry = 0;\n\n await this.processMessage(message);\n }\n catch (error) {\n this.logger.error(`Error processing message: ${error.message}`);\n\n // if an error occurs then if retryCount is set we start retrying. \n if (message) {\n if (message.currentRetry < message.retryCount) {\n await this.updateStatusInDatabase('retrying', message);\n\n message.currentRetry++;\n this.logger.warn(`Retrying message (${message.currentRetry}/${message.retryCount}) after ${message.retryInterval}ms`);\n setTimeout(() => {\n this.retryMessage(message);\n }, message.retryInterval);\n } else {\n // Discard the message after max retries\n await this.updateStatusInDatabase('failed', message, error.message, '');\n this.logger.error(`Message failed after ${message.retryCount} attempts: ${error.message}`);\n }\n }\n }\n // this.logger.debug(`#### DatabaseSubscriber finished processing message from queue: ${queueName}`);\n }\n\n async onModuleInit(): Promise<void> {\n // Not using SettingService here as that will necessitate all implementors of DatabaseSubscriber to also inject SettingService which is not ideal. \n // Instead we directly read the environment variables here.\n const defaultBroker = process.env.QUEUES_DEFAULT_BROKER || 'database';\n const solidCliRunning = process.env.SOLID_CLI_RUNNING || \"false\";\n const queueNameRegex = (process.env.QUEUES_QUEUE_NAME_REGEX_TO_ENABLE || '').trim();\n const roleAllowed = ['both', 'subscriber'].includes(this.serviceRole);\n\n if (!roleAllowed) {\n this.logger.log(`DatabaseSubscriber is disabled because QUEUES_SERVICE_ROLE is \"${this.serviceRole}\". Expected \"both\" or \"subscriber\".`);\n return;\n }\n\n // we will start subscriber only if the current service role is subscriber. \n if (defaultBroker === 'database' && solidCliRunning === \"false\") {\n const options = this.options();\n const queueName = options.queueName;\n\n if (queueNameRegex && queueNameRegex !== \"all\") {\n try {\n const regex = new RegExp(queueNameRegex);\n if (!regex.test(queueName)) {\n this.logger.log(`DatabaseSubscriber for queue ${queueName} is disabled because it does not match QUEUES_QUEUE_NAME_REGEX_TO_ENABLE=${queueNameRegex}`);\n return;\n }\n } catch (error) {\n this.logger.error(`Invalid QUEUES_QUEUE_NAME_REGEX_TO_ENABLE regex \"${queueNameRegex}\". Subscriber for queue ${queueName} will not start.`);\n return;\n }\n }\n\n const namespacedQueueName = buildNamespacedQueueName(queueName);\n this.poller.start(namespacedQueueName, (q) => this.processNext(q), {\n baseDelayMs: 1000,\n maxDelayMs: 30_000,\n timeoutPerIterationMs: 5 * 60_000,\n jitter: true,\n });\n\n this.logger.log(`DatabaseSubscriber ready to consume messages: ${JSON.stringify(this.options())}`);\n }\n }\n\n onModuleDestroy() {\n const options = this.options();\n const queueName = options.queueName;\n const namespacedQueueName = buildNamespacedQueueName(queueName);\n this.poller.stop(namespacedQueueName);\n }\n\n /**\n * Abstract method for message processing logic.\n */\n protected async processMessage(message: QueueMessage<T>): Promise<void> {\n await this.updateStatusInDatabase('started', message);\n\n // Capture the results of handling the task.\n const result = await this.subscribe(message);\n\n // TODO: Update the database to indicate that the task is finished.\n await this.updateStatusInDatabase('succeeded', message, '', result ? JSON.stringify(result, null, 2) : '');\n }\n\n /**\n * Retry the message by invoking the processing logic again.\n */\n private async retryMessage(message: QueueMessage<T>) {\n try {\n await this.processMessage(message);\n } catch (error) {\n if (message.currentRetry < message.retryCount) {\n await this.updateStatusInDatabase('retrying', message);\n\n message.currentRetry++;\n this.logger.warn(`Retrying message (${message.currentRetry}/${message.retryCount}) after ${message.retryInterval}ms: ${error.message}`);\n setTimeout(() => {\n this.retryMessage(message);\n }, message.retryInterval);\n } else {\n this.logger.error(`Message failed after ${message.retryCount} attempts: ${error.message}`);\n\n // TODO: Store the error in the database and update the status accordingly.\n await this.updateStatusInDatabase('failed', message, error.message, '');\n\n }\n }\n }\n\n private async updateStatusInDatabase(stage: string, message: QueueMessage<T>, error: string = '', result: string = '') {\n try {\n this.logger.debug(`Updating message status in database: ${stage} for messageId: ${message.messageId}`);\n\n // 1. resolve the queue first\n const mqMessage = await this.mqMessageService.repo.findOne({\n where: {\n messageId: message.messageId,\n }\n });\n\n if (mqMessage) {\n this.logger.debug(`Found message in database: ${JSON.stringify(mqMessage.messageId)}`);\n this.logger.debug(`Updating message status in database: ${stage} for messageId: ${mqMessage.id}`);\n\n const updatedFields = {\n stage: stage\n };\n if (stage === 'failed' || stage === 'succeeded') {\n updatedFields['finishedAt'] = new Date();\n updatedFields['elapsedMillis'] = updatedFields['finishedAt'].getTime() - mqMessage.startedAt.getTime();\n }\n if (stage === 'succeeded') {\n updatedFields['output'] = result;\n }\n if (stage === 'failed') {\n updatedFields['error'] = error;\n }\n await this.mqMessageService.repo.update(mqMessage.id, updatedFields);\n this.logger.debug(`Message status updated to ${stage} for messageId: ${mqMessage.id}`);\n }\n }\n catch (error) {\n this.logger.error(error.message, error.stack);\n }\n }\n}\n"]}
1
+ {"version":3,"file":"database-subscriber.service.js","sourceRoot":"","sources":["../../../src/services/queues/database-subscriber.service.ts"],"names":[],"mappings":"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","sourcesContent":["import { Logger, OnModuleInit } from '@nestjs/common';\nimport { QueuesModuleOptions } from \"../../interfaces\";\nimport { QueueMessage, QueueSubscriber } from '../../interfaces/mq';\nimport { MqMessageQueueService } from '../mq-message-queue.service';\nimport { MqMessageService } from '../mq-message.service';\nimport { PollerService } from '../poller.service';\nimport { buildNamespacedQueueName } from './common';\n\nexport abstract class DatabaseSubscriber<T> implements OnModuleInit, QueueSubscriber<T> {\n private _loggerInstance?: Logger;\n private readonly url: string;\n private readonly serviceRole: string;\n\n constructor(\n protected readonly mqMessageService: MqMessageService,\n protected readonly mqMessageQueueService: MqMessageQueueService,\n protected readonly poller: PollerService,\n ) {\n this.serviceRole = process.env.QUEUES_SERVICE_ROLE;\n if (!this.serviceRole) {\n this.logger.debug('Queue service Role is not defined in the environment variables');\n }\n // this.logger.debug(`DatabaseSubscriber instance created with options: ${JSON.stringify(this.options())}`);\n }\n\n protected get loggerContext(): string {\n return this.constructor.name;\n }\n\n protected get logger(): Logger {\n if (!this._loggerInstance) {\n this._loggerInstance = new Logger(this.loggerContext);\n }\n return this._loggerInstance;\n }\n\n abstract subscribe(message: QueueMessage<T>): Promise<any>;\n\n abstract options(): QueuesModuleOptions;\n\n private async processNext(queueName: string) {\n // this.logger.debug(`#### DatabaseSubscriber processing next message from queue: ${queueName}`);\n const job = await this.mqMessageService.lockNextPendingMessage(queueName);\n if (!job) {\n return;\n }\n\n const messageContentString = job.input.toString();\n // this.logger.debug(`DatabaseSubscriber Received raw message: ${messageContentString}`);\n\n let message: QueueMessage<T> = null;\n\n try {\n message = JSON.parse(messageContentString) as QueueMessage<T>;\n\n // this is the first time we are receiving the message so we set the currentRetry to 0\n if (!message.retryCount) message.retryCount = 0;\n if (!message.retryInterval) message.retryInterval = 1000;\n if (!message.currentRetry) message.currentRetry = 0;\n\n await this.processMessage(message);\n }\n catch (error) {\n this.logger.error(`Error processing message: ${error.message}`);\n\n // if an error occurs then if retryCount is set we start retrying. \n if (message) {\n if (message.currentRetry < message.retryCount) {\n await this.updateStatusInDatabase('retrying', message);\n\n message.currentRetry++;\n this.logger.warn(`Retrying message (${message.currentRetry}/${message.retryCount}) after ${message.retryInterval}ms`);\n setTimeout(() => {\n this.retryMessage(message);\n }, message.retryInterval);\n } else {\n // Discard the message after max retries\n await this.updateStatusInDatabase('failed', message, error.message, '');\n this.logger.error(`Message failed after ${message.retryCount} attempts: ${error.message}`);\n }\n }\n }\n // this.logger.debug(`#### DatabaseSubscriber finished processing message from queue: ${queueName}`);\n }\n\n async onModuleInit(): Promise<void> {\n // Not using SettingService here as that will necessitate all implementors of DatabaseSubscriber to also inject SettingService which is not ideal. \n // Instead we directly read the environment variables here.\n const defaultBroker = process.env.QUEUES_DEFAULT_BROKER || 'database';\n const solidCliRunning = process.env.SOLID_CLI_RUNNING || \"false\";\n const queueNameRegex = (process.env.QUEUES_QUEUE_NAME_REGEX_TO_ENABLE || '').trim();\n const roleAllowed = ['both', 'subscriber'].includes(this.serviceRole);\n\n if (!roleAllowed) {\n this.logger.log(`DatabaseSubscriber is disabled because QUEUES_SERVICE_ROLE is \"${this.serviceRole}\". Expected \"both\" or \"subscriber\".`);\n return;\n }\n\n // we will start subscriber only if the current service role is subscriber. \n if (defaultBroker === 'database' && solidCliRunning === \"false\") {\n const options = this.options();\n const queueName = options.queueName;\n\n if (queueNameRegex && queueNameRegex !== \"all\") {\n try {\n const regex = new RegExp(queueNameRegex);\n if (!regex.test(queueName)) {\n this.logger.log(`DatabaseSubscriber for queue ${queueName} is disabled because it does not match QUEUES_QUEUE_NAME_REGEX_TO_ENABLE=${queueNameRegex}`);\n return;\n }\n } catch (error) {\n this.logger.error(`Invalid QUEUES_QUEUE_NAME_REGEX_TO_ENABLE regex \"${queueNameRegex}\". Subscriber for queue ${queueName} will not start.`);\n return;\n }\n }\n\n const namespacedQueueName = buildNamespacedQueueName(queueName);\n this.poller.start(namespacedQueueName, (q) => this.processNext(q), {\n baseDelayMs: 1000,\n maxDelayMs: 30_000,\n timeoutPerIterationMs: 5 * 60_000,\n jitter: true,\n });\n\n this.logger.log(`DatabaseSubscriber ready to consume messages: ${JSON.stringify(this.options())}`);\n }\n }\n\n onModuleDestroy() {\n const options = this.options();\n const queueName = options.queueName;\n const namespacedQueueName = buildNamespacedQueueName(queueName);\n this.poller.stop(namespacedQueueName);\n }\n\n /**\n * Abstract method for message processing logic.\n */\n protected async processMessage(message: QueueMessage<T>): Promise<void> {\n await this.updateStatusInDatabase('started', message);\n\n // Capture the results of handling the task.\n const result = await this.subscribe(message);\n\n // TODO: Update the database to indicate that the task is finished.\n await this.updateStatusInDatabase('succeeded', message, '', result ? JSON.stringify(result, null, 2) : '');\n }\n\n /**\n * Retry the message by invoking the processing logic again.\n */\n private async retryMessage(message: QueueMessage<T>) {\n try {\n await this.processMessage(message);\n } catch (error) {\n if (message.currentRetry < message.retryCount) {\n await this.updateStatusInDatabase('retrying', message);\n\n message.currentRetry++;\n this.logger.warn(`Retrying message (${message.currentRetry}/${message.retryCount}) after ${message.retryInterval}ms: ${error.message}`);\n setTimeout(() => {\n this.retryMessage(message);\n }, message.retryInterval);\n } else {\n this.logger.error(`Message failed after ${message.retryCount} attempts: ${error.message}`);\n\n // TODO: Store the error in the database and update the status accordingly.\n await this.updateStatusInDatabase('failed', message, error.message, '');\n\n }\n }\n }\n\n private async updateStatusInDatabase(stage: string, message: QueueMessage<T>, error: string = '', result: string = '') {\n try {\n this.logger.debug(`Updating message status in database: ${stage} for messageId: ${message.messageId}`);\n\n // 1. resolve the queue first\n const mqMessage = await this.mqMessageService.repo.findOne({\n where: {\n messageId: message.messageId,\n }\n });\n\n if (mqMessage) {\n this.logger.debug(`Found message in database: ${JSON.stringify(mqMessage.messageId)}`);\n this.logger.debug(`Updating message status in database: ${stage} for messageId: ${mqMessage.id}`);\n\n const updatedFields = {\n stage: stage\n };\n if (stage === 'failed' || stage === 'succeeded') {\n updatedFields['finishedAt'] = new Date();\n updatedFields['elapsedMillis'] = updatedFields['finishedAt'].getTime() - mqMessage.startedAt.getTime();\n }\n if (stage === 'succeeded') {\n updatedFields['output'] = result;\n }\n if (stage === 'failed') {\n updatedFields['error'] = error;\n }\n await this.mqMessageService.repo.update(mqMessage.id, updatedFields);\n this.logger.debug(`Message status updated to ${stage} for messageId: ${mqMessage.id}`);\n }\n }\n catch (error) {\n this.logger.error(error.message, error.stack);\n }\n }\n}\n"]}
@@ -19,7 +19,7 @@ export declare abstract class RabbitMqSubscriber<T> implements OnModuleInit, Que
19
19
  constructor(mqMessageService: MqMessageService, mqMessageQueueService: MqMessageQueueService);
20
20
  protected get loggerContext(): string;
21
21
  protected get logger(): Logger;
22
- abstract subscribe(message: QueueMessage<T>): any;
22
+ abstract subscribe(message: QueueMessage<T>): Promise<any>;
23
23
  abstract options(): QueuesModuleOptions;
24
24
  protected shouldPersistToDatabase(): boolean;
25
25
  establishConnection(): Promise<amqp.Connection>;
@@ -1 +1 @@
1
- {"version":3,"file":"rabbitmq-subscriber.service.d.ts","sourceRoot":"","sources":["../../../src/services/queues/rabbitmq-subscriber.service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AACtD,OAAO,KAAK,IAAI,MAAM,SAAS,CAAC;AAChC,OAAO,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AACpE,OAAO,EAAE,qBAAqB,EAAE,MAAM,6BAA6B,CAAC;AACpE,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAezD,8BAAsB,kBAAkB,CAAC,CAAC,CAAE,YAAW,YAAY,EAAE,eAAe,CAAC,CAAC,CAAC;IAWvE,SAAS,CAAC,QAAQ,CAAC,gBAAgB,EAAE,gBAAgB;IAAE,SAAS,CAAC,QAAQ,CAAC,qBAAqB,EAAE,qBAAqB;IAVlI,OAAO,CAAC,eAAe,CAAC,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAS;IAC7B,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,UAAU,CAAgC;IAClD,OAAO,CAAC,OAAO,CAA6B;IAC5C,OAAO,CAAC,WAAW,CAAuB;IAC1C,OAAO,CAAC,gBAAgB,CAA8B;IACtD,OAAO,CAAC,gBAAgB,CAAK;IAC7B,OAAO,CAAC,QAAQ,CAAS;gBAEM,gBAAgB,EAAE,gBAAgB,EAAqB,qBAAqB,EAAE,qBAAqB;IAYlI,SAAS,KAAK,aAAa,IAAI,MAAM,CAEpC;IAED,SAAS,KAAK,MAAM,IAAI,MAAM,CAK7B;IAED,QAAQ,CAAC,SAAS,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC,CAAC;IAE3C,QAAQ,CAAC,OAAO,IAAI,mBAAmB;IAEvC,SAAS,CAAC,uBAAuB,IAAI,OAAO;IAItC,mBAAmB,IAAI,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC;IAsB/C,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC;YA2CrB,iBAAiB;YA8GjB,qBAAqB;YAiCrB,oBAAoB;IAclC,OAAO,CAAC,gBAAgB;YAWV,aAAa;YAkBb,OAAO;IAkCrB,OAAO,CAAC,KAAK;IAKb,OAAO,CAAC,OAAO;cAWC,cAAc,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC,CAAC,EAAE,UAAU,KAAA,EAAE,OAAO,KAAA,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;YAkBjG,sBAAsB;IAkCpC,OAAO,CAAC,0BAA0B;IAqBlC,OAAO,CAAC,gBAAgB;YASV,oBAAoB;CAuDrC"}
1
+ {"version":3,"file":"rabbitmq-subscriber.service.d.ts","sourceRoot":"","sources":["../../../src/services/queues/rabbitmq-subscriber.service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AACtD,OAAO,KAAK,IAAI,MAAM,SAAS,CAAC;AAChC,OAAO,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AACpE,OAAO,EAAE,qBAAqB,EAAE,MAAM,6BAA6B,CAAC;AACpE,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAezD,8BAAsB,kBAAkB,CAAC,CAAC,CAAE,YAAW,YAAY,EAAE,eAAe,CAAC,CAAC,CAAC;IAWvE,SAAS,CAAC,QAAQ,CAAC,gBAAgB,EAAE,gBAAgB;IAAE,SAAS,CAAC,QAAQ,CAAC,qBAAqB,EAAE,qBAAqB;IAVlI,OAAO,CAAC,eAAe,CAAC,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAS;IAC7B,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,UAAU,CAAgC;IAClD,OAAO,CAAC,OAAO,CAA6B;IAC5C,OAAO,CAAC,WAAW,CAAuB;IAC1C,OAAO,CAAC,gBAAgB,CAA8B;IACtD,OAAO,CAAC,gBAAgB,CAAK;IAC7B,OAAO,CAAC,QAAQ,CAAS;gBAEM,gBAAgB,EAAE,gBAAgB,EAAqB,qBAAqB,EAAE,qBAAqB;IAYlI,SAAS,KAAK,aAAa,IAAI,MAAM,CAEpC;IAED,SAAS,KAAK,MAAM,IAAI,MAAM,CAK7B;IAED,QAAQ,CAAC,SAAS,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC;IAE1D,QAAQ,CAAC,OAAO,IAAI,mBAAmB;IAEvC,SAAS,CAAC,uBAAuB,IAAI,OAAO;IAItC,mBAAmB,IAAI,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC;IAsB/C,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC;YA2CrB,iBAAiB;YA8GjB,qBAAqB;YAiCrB,oBAAoB;IAclC,OAAO,CAAC,gBAAgB;YAWV,aAAa;YAkBb,OAAO;IAkCrB,OAAO,CAAC,KAAK;IAKb,OAAO,CAAC,OAAO;cAWC,cAAc,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC,CAAC,EAAE,UAAU,KAAA,EAAE,OAAO,KAAA,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;YAkBjG,sBAAsB;IAkCpC,OAAO,CAAC,0BAA0B;IAqBlC,OAAO,CAAC,gBAAgB;YASV,oBAAoB;CAyDrC"}
@@ -380,7 +380,9 @@ class RabbitMqSubscriber {
380
380
  }
381
381
  let timedOut = false;
382
382
  let timeoutHandle = null;
383
- const subscribePromise = this.subscribe(message).catch((error) => {
383
+ const subscribePromise = Promise.resolve()
384
+ .then(() => this.subscribe(message))
385
+ .catch((error) => {
384
386
  if (timedOut) {
385
387
  this.logger.error(`Subscriber promise rejected after timeout for queue ${queueName} and messageId ${messageId}: ${error?.message || String(error)}`, error?.stack);
386
388
  return undefined;
@@ -1 +1 @@
1
- {"version":3,"file":"rabbitmq-subscriber.service.js","sourceRoot":"","sources":["../../../src/services/queues/rabbitmq-subscriber.service.ts"],"names":[],"mappings":"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","sourcesContent":["import { Logger, OnModuleInit } from '@nestjs/common';\nimport * as amqp from 'amqplib';\nimport { QueuesModuleOptions } from \"../../interfaces\";\nimport { QueueMessage, QueueSubscriber } from '../../interfaces/mq';\nimport { MqMessageQueueService } from '../mq-message-queue.service';\nimport { MqMessageService } from '../mq-message.service';\nimport { buildNamespacedQueueName } from './common';\n\nclass ConsumerProcessingTimeoutError extends Error {\n constructor(\n readonly queueName: string,\n readonly messageId: string,\n readonly timeoutMs: number,\n ) {\n super(`Subscriber processing timed out after ${timeoutMs}ms for queue ${queueName} and messageId ${messageId}`);\n this.name = 'ConsumerProcessingTimeoutError';\n }\n}\n\n\nexport abstract class RabbitMqSubscriber<T> implements OnModuleInit, QueueSubscriber<T> { // TODO This can be made a generic type for better type visibility\n private _loggerInstance?: Logger;\n private readonly url: string;\n private readonly serviceRole: string;\n private connection: amqp.Connection | null = null;\n private channel: amqp.Channel | null = null;\n private consumerTag: string | null = null;\n private reconnectPromise: Promise<void> | null = null;\n private reconnectAttempt = 0;\n private stopping = false;\n\n constructor(protected readonly mqMessageService: MqMessageService, protected readonly mqMessageQueueService: MqMessageQueueService) {\n this.url = process.env.QUEUES_RABBIT_MQ_URL;\n this.serviceRole = process.env.QUEUES_SERVICE_ROLE;\n if (!this.url) {\n this.logger.debug('RabbitMqPublisher url is not defined in the environment variables');\n }\n if (!this.serviceRole) {\n this.logger.debug('Queue service Role is not defined in the environment variables');\n }\n // this.logger.debug(`RabbitMqSubscriber instance created with options: ${JSON.stringify(this.options())} and url: ${this.url}`);\n }\n\n protected get loggerContext(): string {\n return this.constructor.name;\n }\n\n protected get logger(): Logger {\n if (!this._loggerInstance) {\n this._loggerInstance = new Logger(this.loggerContext);\n }\n return this._loggerInstance;\n }\n\n abstract subscribe(message: QueueMessage<T>);\n\n abstract options(): QueuesModuleOptions;\n\n protected shouldPersistToDatabase(): boolean {\n return this.options().persistToDatabase ?? true;\n }\n\n async establishConnection(): Promise<amqp.Connection> {\n\n const url = new URL(this.url);\n\n // this.logger.debug(`user: ${url.username}`);\n // // just for local debug, don’t log in prod\n // this.logger.debug(`pass: ${url.password}`);\n // this.logger.debug(`path (vhost): ${url.pathname}`);\n\n const connection = await amqp.connect({\n protocol: url.protocol.replace(':', ''),\n hostname: url.hostname,\n port: parseInt(url.port),\n username: url.username,\n password: decodeURIComponent(url.password),\n frameMax: 131072,\n heartbeat: 30,\n });\n\n return connection\n }\n\n async onModuleInit(): Promise<void> {\n // Not using SettingService here as that will necessitate all implementors of RabbitMqSubscriber to also inject SettingService which is not ideal. \n // Instead we directly read the environment variables here.\n const defaultBroker = process.env.QUEUES_DEFAULT_BROKER || 'rabbitmq';\n const solidCliRunning = process.env.SOLID_CLI_RUNNING || \"false\";\n const queueNameRegex = (process.env.QUEUES_QUEUE_NAME_REGEX_TO_ENABLE || '').trim();\n const roleAllowed = ['both', 'subscriber'].includes(this.serviceRole);\n\n if (!roleAllowed) {\n this.logger.log(`RabbitMqSubscriber is disabled because QUEUES_SERVICE_ROLE is \"${this.serviceRole}\". Expected \"both\" or \"subscriber\".`);\n return;\n }\n\n // we will start subscriber only if the current service role is subscriber. \n if (this.url && solidCliRunning === \"false\" && defaultBroker === 'rabbitmq') {\n const options = this.options();\n const queueName = options.queueName;\n\n if (queueNameRegex && queueNameRegex !== \"all\") {\n try {\n const regex = new RegExp(queueNameRegex);\n if (!regex.test(queueName)) {\n this.logger.log(`RabbitMqSubscriber for queue ${queueName} is disabled because it does not match QUEUES_QUEUE_NAME_REGEX_TO_ENABLE=${queueNameRegex}`);\n return;\n }\n } catch (error) {\n this.logger.error(`Invalid QUEUES_QUEUE_NAME_REGEX_TO_ENABLE regex \"${queueNameRegex}\". Subscriber for queue ${queueName} will not start.`);\n return;\n }\n }\n\n const namespacedQueueName = buildNamespacedQueueName(queueName);\n try {\n await this.connectAndConsume(namespacedQueueName);\n } catch (err) {\n this.logger.error(`Failed to connect to RabbitMQ for queue ${namespacedQueueName}: ${(err as Error).message}`, (err as Error).stack);\n this.triggerReconnect(namespacedQueueName, 'initial connection failure');\n }\n\n this.logger.log(`RabbitMqSubscriber ready to consume messages: ${JSON.stringify(options)} and url: ${this.url}`);\n }\n }\n\n private async connectAndConsume(queueName: string): Promise<void> {\n await this.cleanup();\n this.logger.log(`RabbitMqSubscriber in connectAndConsume for queue: ${queueName} and url: ${this.url}`);\n\n const options = this.options();\n const prefetch = options.prefetch ?? 1;\n if (prefetch < 1) {\n throw new Error(`RabbitMqSubscriber prefetch must be >= 1 for queue ${queueName}`);\n }\n const processingTimeoutMs = this.resolveProcessingTimeoutMs();\n if (processingTimeoutMs > 0) {\n this.logger.log(`RabbitMqSubscriber using processing timeout ${processingTimeoutMs}ms for queue ${queueName}`);\n }\n\n let connection: amqp.Connection;\n try {\n connection = await this.establishConnection();\n } catch (err) {\n this.logger.error(`Failed to connect to RabbitMQ for queue ${queueName}: ${(err as Error).message}`, (err as Error).stack);\n throw err;\n }\n\n this.connection = connection;\n\n connection.on('error', (err) => {\n if (connection !== this.connection) return;\n this.logger.error(`RabbitMqSubscriber connection error for queue ${queueName}: ${(err as Error).message}`);\n });\n\n connection.on('close', () => {\n if (connection !== this.connection) return;\n this.logger.warn(`RabbitMqSubscriber connection closed for queue ${queueName}`);\n this.triggerReconnect(queueName, 'connection closed');\n });\n\n const channel = await connection.createChannel();\n this.channel = channel;\n\n channel.on('error', (err) => {\n if (channel !== this.channel) return;\n this.logger.error(`RabbitMqSubscriber channel error for queue ${queueName}: ${(err as Error).message}`);\n });\n\n channel.on('close', () => {\n if (channel !== this.channel) return;\n this.logger.warn(`RabbitMqSubscriber channel closed for queue ${queueName}`);\n this.triggerReconnect(queueName, 'channel closed');\n });\n\n // Process one message at a time per consumer to avoid parallel work on the same subscriber instance.\n await channel.prefetch(prefetch);\n\n // Use a direct exchange with a stable routing key so retry DLX can route back to the main queue.\n const exchangeName = `${queueName}.exchange`;\n const routingKey = `${queueName}.routing-key`;\n const retryQueue = `${queueName}.retry`;\n const failedQueue = `${queueName}.failed`;\n\n await channel.assertExchange(exchangeName, 'direct', {});\n await channel.assertQueue(queueName, {});\n await channel.bindQueue(queueName, exchangeName, routingKey);\n\n // Retry queue uses DLX to route expired messages back to the main exchange/routing key.\n await channel.assertQueue(retryQueue, {\n arguments: {\n 'x-dead-letter-exchange': exchangeName,\n 'x-dead-letter-routing-key': routingKey,\n }\n });\n\n await channel.assertQueue(failedQueue, {});\n\n const consumeResult = await channel.consume(\n queueName,\n async (rawMessage) => {\n if (!rawMessage) {\n return;\n }\n\n let message: QueueMessage<T> = null;\n\n try {\n const messageContentString = rawMessage.content.toString();\n message = JSON.parse(messageContentString) as QueueMessage<T>;\n this.logger.debug(`rabbitmq subscriber received message with id: ${message.messageId} for queue ${queueName}`);\n } catch (error) {\n this.logger.error(`Invalid JSON message on queue ${queueName}: ${(error as Error).message}`);\n await this.publishToFailedQueue(queueName, rawMessage.content, channel, error);\n channel.ack(rawMessage);\n return;\n }\n\n if (!message.retryCount) message.retryCount = 0;\n if (!message.retryInterval) message.retryInterval = 1000;\n if (!message.currentRetry) message.currentRetry = 0;\n\n try {\n await this.processMessage(message, rawMessage, channel, queueName);\n } catch (error) {\n await this.handleProcessingError(message, rawMessage, channel, error, queueName);\n }\n },\n // Explicit ack enables reliable processing and retry routing.\n { noAck: false },\n );\n\n this.consumerTag = consumeResult.consumerTag;\n }\n\n // Retry flow: update DB -> increment retry -> send to retry queue with per-message expiration -> ack original.\n private async handleProcessingError(message: QueueMessage<T>, rawMessage: amqp.ConsumeMessage, channel: amqp.Channel, error: any, queueName: string): Promise<void> {\n const errorMessage = (error as Error)?.message || String(error);\n this.logger.error(`Error processing message on queue ${queueName}: ${errorMessage}`, (error as Error)?.stack);\n\n if (message.currentRetry < message.retryCount) {\n if (this.shouldPersistToDatabase()) {\n await this.updateStatusInDatabase('retrying', message);\n }\n\n message.currentRetry++;\n const retryQueue = `${queueName}.retry`;\n const payload = Buffer.from(JSON.stringify(message));\n\n // Per-message expiration keeps the message in the retry queue until TTL, then DLX routes it back.\n channel.sendToQueue(retryQueue, payload, {\n expiration: String(message.retryInterval || 1000),\n headers: {\n 'x-error': errorMessage,\n }\n });\n\n channel.ack(rawMessage);\n this.logger.warn(`Retrying message (${message.currentRetry}/${message.retryCount}) after ${message.retryInterval}ms on queue ${queueName}`);\n return;\n }\n if (this.shouldPersistToDatabase()) {\n await this.updateStatusInDatabase('failed', message, errorMessage, '');\n }\n channel.ack(rawMessage);\n await this.publishToFailedQueue(queueName, Buffer.from(JSON.stringify(message)), channel, error);\n this.logger.error(`Message failed after ${message.retryCount} attempts on queue ${queueName}: ${errorMessage}`);\n }\n\n private async publishToFailedQueue(queueName: string, payload: Buffer | string, channel: amqp.Channel, error?: any): Promise<void> {\n const failedQueue = `${queueName}.failed`;\n const body = Buffer.isBuffer(payload) ? payload : Buffer.from(payload);\n const errorMessage = (error as Error)?.message || String(error || '');\n\n try {\n channel.sendToQueue(failedQueue, body, errorMessage ? {\n headers: { 'x-error': errorMessage }\n } : undefined);\n } catch (err) {\n this.logger.error(`Failed to publish to failed queue ${failedQueue}: ${(err as Error).message}`);\n }\n }\n\n private triggerReconnect(queueName: string, reason: string) {\n if (this.stopping) return;\n if (this.reconnectPromise) return;\n\n this.reconnectPromise = this.reconnectLoop(queueName, reason)\n .finally(() => {\n this.reconnectPromise = null;\n });\n }\n\n // Reconnect with backoff to avoid hammering the broker during outages.\n private async reconnectLoop(queueName: string, reason: string): Promise<void> {\n this.logger.warn(`RabbitMqSubscriber reconnecting for queue ${queueName}: ${reason}`);\n\n while (!this.stopping) {\n try {\n await this.connectAndConsume(queueName);\n this.reconnectAttempt = 0;\n this.logger.log(`RabbitMqSubscriber reconnected for queue ${queueName}`);\n return;\n } catch (err) {\n this.reconnectAttempt += 1;\n const delay = this.backoff();\n this.logger.warn(`RabbitMqSubscriber reconnect failed for queue ${queueName}; retrying in ${delay}ms`);\n await this.sleep(delay);\n }\n }\n }\n\n private async cleanup(): Promise<void> {\n const channel = this.channel;\n const connection = this.connection;\n const consumerTag = this.consumerTag;\n\n this.channel = null;\n this.connection = null;\n this.consumerTag = null;\n\n if (channel) {\n try {\n if (consumerTag) {\n await channel.cancel(consumerTag);\n }\n } catch (_) {\n // ignore\n }\n\n try {\n await channel.close();\n } catch (_) {\n // ignore\n }\n }\n\n if (connection) {\n try {\n await connection.close();\n } catch (_) {\n // ignore\n }\n }\n }\n\n private sleep(ms: number): Promise<void> {\n return new Promise(resolve => setTimeout(resolve, ms));\n }\n\n // Exponential backoff with jitter, capped to 30s.\n private backoff(): number {\n const baseMs = 1000;\n const maxMs = 30_000;\n const exp = Math.min(maxMs, baseMs * Math.pow(2, this.reconnectAttempt));\n const jitter = Math.floor(Math.random() * (exp * 0.2));\n return Math.min(maxMs, exp + jitter);\n }\n\n /**\n * Abstract method for message processing logic.\n */\n protected async processMessage(message: QueueMessage<T>, rawMessage, channel, queueName: string): Promise<void> {\n if (this.shouldPersistToDatabase()) {\n await this.updateStatusInDatabase('started', message);\n }\n\n // Capture the results of handling the task.\n const result = await this.subscribeWithTimeout(message, queueName);\n\n // Ack the message. \n channel.ack(rawMessage);\n\n // Persist success output and timing.\n if (this.shouldPersistToDatabase()) {\n await this.updateStatusInDatabase('succeeded', message, '', result ? JSON.stringify(result, null, 2) : '');\n }\n\n }\n\n private async updateStatusInDatabase(stage: string, message: QueueMessage<T>, error: string = '', result: string = '') {\n\n // Update the existing message record by messageId; creation happens upstream.\n try {\n // 1. resolve the queue first\n const mqMessage = await this.mqMessageService.repo.findOne({\n where: {\n messageId: message.messageId,\n }\n });\n\n if (mqMessage) {\n const updatedFields = {\n stage: stage\n };\n if (stage === 'failed' || stage === 'succeeded') {\n updatedFields['finishedAt'] = new Date();\n updatedFields['elapsedMillis'] = updatedFields['finishedAt'].getTime() - mqMessage.startedAt.getTime();\n }\n if (stage === 'succeeded') {\n updatedFields['output'] = result;\n }\n if (stage === 'failed') {\n updatedFields['error'] = error;\n }\n await this.mqMessageService.repo.update(mqMessage.id, updatedFields);\n }\n }\n catch (error) {\n this.logger.error(error.message, error.stack);\n }\n\n }\n\n private resolveProcessingTimeoutMs(): number {\n // Broker-side delivery-ack timeout (ms). If not provided, assume RabbitMQ default\n // behavior used in this project: 30 minutes.\n // Example (RabbitMQ broker):\n // - Broker ack timeout: 30m => 1,800,000ms (QUEUES_RABBITMQ_CONSUMER_ACK_TIMEOUT_MS)\n // - App soft timeout should be slightly lower, e.g. 29m30s => 1,770,000ms\n // (QUEUES_RABBITMQ_SUBSCRIBER_PROCESSING_TIMEOUT_MS), so application code fails first,\n // records DB state/error, and avoids broker-forced channel close as primary failure signal.\n const brokerTimeoutMs = this.parsePositiveInt(process.env.QUEUES_RABBITMQ_CONSUMER_ACK_TIMEOUT_MS, 30 * 60 * 1000);\n\n // Soft timeout should fire *before* broker timeout so we can fail explicitly,\n // persist status/error, and avoid broker-forced channel closure as primary signal.\n // Keep at least 1s to avoid zero/negative values when broker timeout is very small.\n const defaultSoftTimeoutMs = Math.max(1_000, brokerTimeoutMs - 30_000);\n\n // Final timeout precedence:\n // 1) QUEUES_RABBITMQ_SUBSCRIBER_PROCESSING_TIMEOUT_MS (if valid positive int)\n // 2) Derived defaultSoftTimeoutMs (broker timeout - 30s)\n return this.parsePositiveInt(process.env.QUEUES_RABBITMQ_SUBSCRIBER_PROCESSING_TIMEOUT_MS, defaultSoftTimeoutMs);\n }\n\n private parsePositiveInt(value: string | undefined, fallback: number): number {\n // Shared env parsing helper:\n // - missing/invalid/non-positive => fallback\n // - valid positive integer => parsed value\n if (!value) return fallback;\n const parsed = Number.parseInt(value, 10);\n return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback;\n }\n\n private async subscribeWithTimeout(message: QueueMessage<T>, queueName: string): Promise<any> {\n const timeoutMs = this.resolveProcessingTimeoutMs();\n const messageId = message?.messageId || 'unknown';\n\n // Allow an escape hatch: non-positive timeout means run without a soft timeout.\n if (timeoutMs <= 0) {\n return this.subscribe(message);\n }\n\n let timedOut = false;\n let timeoutHandle: NodeJS.Timeout | null = null;\n\n // Main subscriber work promise.\n // If timeout has already fired, suppress rethrow to avoid unhandled rejection noise\n // (the timeout error is already the authoritative failure we track).\n const subscribePromise = this.subscribe(message).catch((error) => {\n if (timedOut) {\n this.logger.error(\n `Subscriber promise rejected after timeout for queue ${queueName} and messageId ${messageId}: ${(error as Error)?.message || String(error)}`,\n (error as Error)?.stack,\n );\n return undefined;\n }\n throw error;\n });\n\n // Timeout promise rejects after timeoutMs with an explicit domain-specific error.\n const timeoutPromise = new Promise<never>((_, reject) => {\n timeoutHandle = setTimeout(() => {\n timedOut = true;\n reject(new ConsumerProcessingTimeoutError(queueName, messageId, timeoutMs));\n }, timeoutMs);\n });\n\n try {\n // Promise.race settles as soon as the *first* promise settles.\n // - If subscribePromise resolves/rejects first, we use that outcome.\n // - If timeoutPromise rejects first, we fail fast with timeout error.\n // This ensures we mark DB status via normal error handling before broker ack-timeout.\n return await Promise.race([subscribePromise, timeoutPromise]);\n } catch (error) {\n const errorMessage = (error as Error)?.message || String(error);\n this.logger.error(\n `Subscriber execution failed for queue ${queueName} and messageId ${messageId}: ${errorMessage}`,\n (error as Error)?.stack,\n );\n throw error;\n } finally {\n // Always clear timer once race settles to avoid timer leaks.\n if (timeoutHandle) {\n clearTimeout(timeoutHandle);\n }\n }\n }\n\n}\n"]}
1
+ {"version":3,"file":"rabbitmq-subscriber.service.js","sourceRoot":"","sources":["../../../src/services/queues/rabbitmq-subscriber.service.ts"],"names":[],"mappings":"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","sourcesContent":["import { Logger, OnModuleInit } from '@nestjs/common';\nimport * as amqp from 'amqplib';\nimport { QueuesModuleOptions } from \"../../interfaces\";\nimport { QueueMessage, QueueSubscriber } from '../../interfaces/mq';\nimport { MqMessageQueueService } from '../mq-message-queue.service';\nimport { MqMessageService } from '../mq-message.service';\nimport { buildNamespacedQueueName } from './common';\n\nclass ConsumerProcessingTimeoutError extends Error {\n constructor(\n readonly queueName: string,\n readonly messageId: string,\n readonly timeoutMs: number,\n ) {\n super(`Subscriber processing timed out after ${timeoutMs}ms for queue ${queueName} and messageId ${messageId}`);\n this.name = 'ConsumerProcessingTimeoutError';\n }\n}\n\n\nexport abstract class RabbitMqSubscriber<T> implements OnModuleInit, QueueSubscriber<T> { // TODO This can be made a generic type for better type visibility\n private _loggerInstance?: Logger;\n private readonly url: string;\n private readonly serviceRole: string;\n private connection: amqp.Connection | null = null;\n private channel: amqp.Channel | null = null;\n private consumerTag: string | null = null;\n private reconnectPromise: Promise<void> | null = null;\n private reconnectAttempt = 0;\n private stopping = false;\n\n constructor(protected readonly mqMessageService: MqMessageService, protected readonly mqMessageQueueService: MqMessageQueueService) {\n this.url = process.env.QUEUES_RABBIT_MQ_URL;\n this.serviceRole = process.env.QUEUES_SERVICE_ROLE;\n if (!this.url) {\n this.logger.debug('RabbitMqPublisher url is not defined in the environment variables');\n }\n if (!this.serviceRole) {\n this.logger.debug('Queue service Role is not defined in the environment variables');\n }\n // this.logger.debug(`RabbitMqSubscriber instance created with options: ${JSON.stringify(this.options())} and url: ${this.url}`);\n }\n\n protected get loggerContext(): string {\n return this.constructor.name;\n }\n\n protected get logger(): Logger {\n if (!this._loggerInstance) {\n this._loggerInstance = new Logger(this.loggerContext);\n }\n return this._loggerInstance;\n }\n\n abstract subscribe(message: QueueMessage<T>): Promise<any>;\n\n abstract options(): QueuesModuleOptions;\n\n protected shouldPersistToDatabase(): boolean {\n return this.options().persistToDatabase ?? true;\n }\n\n async establishConnection(): Promise<amqp.Connection> {\n\n const url = new URL(this.url);\n\n // this.logger.debug(`user: ${url.username}`);\n // // just for local debug, don’t log in prod\n // this.logger.debug(`pass: ${url.password}`);\n // this.logger.debug(`path (vhost): ${url.pathname}`);\n\n const connection = await amqp.connect({\n protocol: url.protocol.replace(':', ''),\n hostname: url.hostname,\n port: parseInt(url.port),\n username: url.username,\n password: decodeURIComponent(url.password),\n frameMax: 131072,\n heartbeat: 30,\n });\n\n return connection\n }\n\n async onModuleInit(): Promise<void> {\n // Not using SettingService here as that will necessitate all implementors of RabbitMqSubscriber to also inject SettingService which is not ideal. \n // Instead we directly read the environment variables here.\n const defaultBroker = process.env.QUEUES_DEFAULT_BROKER || 'rabbitmq';\n const solidCliRunning = process.env.SOLID_CLI_RUNNING || \"false\";\n const queueNameRegex = (process.env.QUEUES_QUEUE_NAME_REGEX_TO_ENABLE || '').trim();\n const roleAllowed = ['both', 'subscriber'].includes(this.serviceRole);\n\n if (!roleAllowed) {\n this.logger.log(`RabbitMqSubscriber is disabled because QUEUES_SERVICE_ROLE is \"${this.serviceRole}\". Expected \"both\" or \"subscriber\".`);\n return;\n }\n\n // we will start subscriber only if the current service role is subscriber. \n if (this.url && solidCliRunning === \"false\" && defaultBroker === 'rabbitmq') {\n const options = this.options();\n const queueName = options.queueName;\n\n if (queueNameRegex && queueNameRegex !== \"all\") {\n try {\n const regex = new RegExp(queueNameRegex);\n if (!regex.test(queueName)) {\n this.logger.log(`RabbitMqSubscriber for queue ${queueName} is disabled because it does not match QUEUES_QUEUE_NAME_REGEX_TO_ENABLE=${queueNameRegex}`);\n return;\n }\n } catch (error) {\n this.logger.error(`Invalid QUEUES_QUEUE_NAME_REGEX_TO_ENABLE regex \"${queueNameRegex}\". Subscriber for queue ${queueName} will not start.`);\n return;\n }\n }\n\n const namespacedQueueName = buildNamespacedQueueName(queueName);\n try {\n await this.connectAndConsume(namespacedQueueName);\n } catch (err) {\n this.logger.error(`Failed to connect to RabbitMQ for queue ${namespacedQueueName}: ${(err as Error).message}`, (err as Error).stack);\n this.triggerReconnect(namespacedQueueName, 'initial connection failure');\n }\n\n this.logger.log(`RabbitMqSubscriber ready to consume messages: ${JSON.stringify(options)} and url: ${this.url}`);\n }\n }\n\n private async connectAndConsume(queueName: string): Promise<void> {\n await this.cleanup();\n this.logger.log(`RabbitMqSubscriber in connectAndConsume for queue: ${queueName} and url: ${this.url}`);\n\n const options = this.options();\n const prefetch = options.prefetch ?? 1;\n if (prefetch < 1) {\n throw new Error(`RabbitMqSubscriber prefetch must be >= 1 for queue ${queueName}`);\n }\n const processingTimeoutMs = this.resolveProcessingTimeoutMs();\n if (processingTimeoutMs > 0) {\n this.logger.log(`RabbitMqSubscriber using processing timeout ${processingTimeoutMs}ms for queue ${queueName}`);\n }\n\n let connection: amqp.Connection;\n try {\n connection = await this.establishConnection();\n } catch (err) {\n this.logger.error(`Failed to connect to RabbitMQ for queue ${queueName}: ${(err as Error).message}`, (err as Error).stack);\n throw err;\n }\n\n this.connection = connection;\n\n connection.on('error', (err) => {\n if (connection !== this.connection) return;\n this.logger.error(`RabbitMqSubscriber connection error for queue ${queueName}: ${(err as Error).message}`);\n });\n\n connection.on('close', () => {\n if (connection !== this.connection) return;\n this.logger.warn(`RabbitMqSubscriber connection closed for queue ${queueName}`);\n this.triggerReconnect(queueName, 'connection closed');\n });\n\n const channel = await connection.createChannel();\n this.channel = channel;\n\n channel.on('error', (err) => {\n if (channel !== this.channel) return;\n this.logger.error(`RabbitMqSubscriber channel error for queue ${queueName}: ${(err as Error).message}`);\n });\n\n channel.on('close', () => {\n if (channel !== this.channel) return;\n this.logger.warn(`RabbitMqSubscriber channel closed for queue ${queueName}`);\n this.triggerReconnect(queueName, 'channel closed');\n });\n\n // Process one message at a time per consumer to avoid parallel work on the same subscriber instance.\n await channel.prefetch(prefetch);\n\n // Use a direct exchange with a stable routing key so retry DLX can route back to the main queue.\n const exchangeName = `${queueName}.exchange`;\n const routingKey = `${queueName}.routing-key`;\n const retryQueue = `${queueName}.retry`;\n const failedQueue = `${queueName}.failed`;\n\n await channel.assertExchange(exchangeName, 'direct', {});\n await channel.assertQueue(queueName, {});\n await channel.bindQueue(queueName, exchangeName, routingKey);\n\n // Retry queue uses DLX to route expired messages back to the main exchange/routing key.\n await channel.assertQueue(retryQueue, {\n arguments: {\n 'x-dead-letter-exchange': exchangeName,\n 'x-dead-letter-routing-key': routingKey,\n }\n });\n\n await channel.assertQueue(failedQueue, {});\n\n const consumeResult = await channel.consume(\n queueName,\n async (rawMessage) => {\n if (!rawMessage) {\n return;\n }\n\n let message: QueueMessage<T> = null;\n\n try {\n const messageContentString = rawMessage.content.toString();\n message = JSON.parse(messageContentString) as QueueMessage<T>;\n this.logger.debug(`rabbitmq subscriber received message with id: ${message.messageId} for queue ${queueName}`);\n } catch (error) {\n this.logger.error(`Invalid JSON message on queue ${queueName}: ${(error as Error).message}`);\n await this.publishToFailedQueue(queueName, rawMessage.content, channel, error);\n channel.ack(rawMessage);\n return;\n }\n\n if (!message.retryCount) message.retryCount = 0;\n if (!message.retryInterval) message.retryInterval = 1000;\n if (!message.currentRetry) message.currentRetry = 0;\n\n try {\n await this.processMessage(message, rawMessage, channel, queueName);\n } catch (error) {\n await this.handleProcessingError(message, rawMessage, channel, error, queueName);\n }\n },\n // Explicit ack enables reliable processing and retry routing.\n { noAck: false },\n );\n\n this.consumerTag = consumeResult.consumerTag;\n }\n\n // Retry flow: update DB -> increment retry -> send to retry queue with per-message expiration -> ack original.\n private async handleProcessingError(message: QueueMessage<T>, rawMessage: amqp.ConsumeMessage, channel: amqp.Channel, error: any, queueName: string): Promise<void> {\n const errorMessage = (error as Error)?.message || String(error);\n this.logger.error(`Error processing message on queue ${queueName}: ${errorMessage}`, (error as Error)?.stack);\n\n if (message.currentRetry < message.retryCount) {\n if (this.shouldPersistToDatabase()) {\n await this.updateStatusInDatabase('retrying', message);\n }\n\n message.currentRetry++;\n const retryQueue = `${queueName}.retry`;\n const payload = Buffer.from(JSON.stringify(message));\n\n // Per-message expiration keeps the message in the retry queue until TTL, then DLX routes it back.\n channel.sendToQueue(retryQueue, payload, {\n expiration: String(message.retryInterval || 1000),\n headers: {\n 'x-error': errorMessage,\n }\n });\n\n channel.ack(rawMessage);\n this.logger.warn(`Retrying message (${message.currentRetry}/${message.retryCount}) after ${message.retryInterval}ms on queue ${queueName}`);\n return;\n }\n if (this.shouldPersistToDatabase()) {\n await this.updateStatusInDatabase('failed', message, errorMessage, '');\n }\n channel.ack(rawMessage);\n await this.publishToFailedQueue(queueName, Buffer.from(JSON.stringify(message)), channel, error);\n this.logger.error(`Message failed after ${message.retryCount} attempts on queue ${queueName}: ${errorMessage}`);\n }\n\n private async publishToFailedQueue(queueName: string, payload: Buffer | string, channel: amqp.Channel, error?: any): Promise<void> {\n const failedQueue = `${queueName}.failed`;\n const body = Buffer.isBuffer(payload) ? payload : Buffer.from(payload);\n const errorMessage = (error as Error)?.message || String(error || '');\n\n try {\n channel.sendToQueue(failedQueue, body, errorMessage ? {\n headers: { 'x-error': errorMessage }\n } : undefined);\n } catch (err) {\n this.logger.error(`Failed to publish to failed queue ${failedQueue}: ${(err as Error).message}`);\n }\n }\n\n private triggerReconnect(queueName: string, reason: string) {\n if (this.stopping) return;\n if (this.reconnectPromise) return;\n\n this.reconnectPromise = this.reconnectLoop(queueName, reason)\n .finally(() => {\n this.reconnectPromise = null;\n });\n }\n\n // Reconnect with backoff to avoid hammering the broker during outages.\n private async reconnectLoop(queueName: string, reason: string): Promise<void> {\n this.logger.warn(`RabbitMqSubscriber reconnecting for queue ${queueName}: ${reason}`);\n\n while (!this.stopping) {\n try {\n await this.connectAndConsume(queueName);\n this.reconnectAttempt = 0;\n this.logger.log(`RabbitMqSubscriber reconnected for queue ${queueName}`);\n return;\n } catch (err) {\n this.reconnectAttempt += 1;\n const delay = this.backoff();\n this.logger.warn(`RabbitMqSubscriber reconnect failed for queue ${queueName}; retrying in ${delay}ms`);\n await this.sleep(delay);\n }\n }\n }\n\n private async cleanup(): Promise<void> {\n const channel = this.channel;\n const connection = this.connection;\n const consumerTag = this.consumerTag;\n\n this.channel = null;\n this.connection = null;\n this.consumerTag = null;\n\n if (channel) {\n try {\n if (consumerTag) {\n await channel.cancel(consumerTag);\n }\n } catch (_) {\n // ignore\n }\n\n try {\n await channel.close();\n } catch (_) {\n // ignore\n }\n }\n\n if (connection) {\n try {\n await connection.close();\n } catch (_) {\n // ignore\n }\n }\n }\n\n private sleep(ms: number): Promise<void> {\n return new Promise(resolve => setTimeout(resolve, ms));\n }\n\n // Exponential backoff with jitter, capped to 30s.\n private backoff(): number {\n const baseMs = 1000;\n const maxMs = 30_000;\n const exp = Math.min(maxMs, baseMs * Math.pow(2, this.reconnectAttempt));\n const jitter = Math.floor(Math.random() * (exp * 0.2));\n return Math.min(maxMs, exp + jitter);\n }\n\n /**\n * Abstract method for message processing logic.\n */\n protected async processMessage(message: QueueMessage<T>, rawMessage, channel, queueName: string): Promise<void> {\n if (this.shouldPersistToDatabase()) {\n await this.updateStatusInDatabase('started', message);\n }\n\n // Capture the results of handling the task.\n const result = await this.subscribeWithTimeout(message, queueName);\n\n // Ack the message. \n channel.ack(rawMessage);\n\n // Persist success output and timing.\n if (this.shouldPersistToDatabase()) {\n await this.updateStatusInDatabase('succeeded', message, '', result ? JSON.stringify(result, null, 2) : '');\n }\n\n }\n\n private async updateStatusInDatabase(stage: string, message: QueueMessage<T>, error: string = '', result: string = '') {\n\n // Update the existing message record by messageId; creation happens upstream.\n try {\n // 1. resolve the queue first\n const mqMessage = await this.mqMessageService.repo.findOne({\n where: {\n messageId: message.messageId,\n }\n });\n\n if (mqMessage) {\n const updatedFields = {\n stage: stage\n };\n if (stage === 'failed' || stage === 'succeeded') {\n updatedFields['finishedAt'] = new Date();\n updatedFields['elapsedMillis'] = updatedFields['finishedAt'].getTime() - mqMessage.startedAt.getTime();\n }\n if (stage === 'succeeded') {\n updatedFields['output'] = result;\n }\n if (stage === 'failed') {\n updatedFields['error'] = error;\n }\n await this.mqMessageService.repo.update(mqMessage.id, updatedFields);\n }\n }\n catch (error) {\n this.logger.error(error.message, error.stack);\n }\n\n }\n\n private resolveProcessingTimeoutMs(): number {\n // Broker-side delivery-ack timeout (ms). If not provided, assume RabbitMQ default\n // behavior used in this project: 30 minutes.\n // Example (RabbitMQ broker):\n // - Broker ack timeout: 30m => 1,800,000ms (QUEUES_RABBITMQ_CONSUMER_ACK_TIMEOUT_MS)\n // - App soft timeout should be slightly lower, e.g. 29m30s => 1,770,000ms\n // (QUEUES_RABBITMQ_SUBSCRIBER_PROCESSING_TIMEOUT_MS), so application code fails first,\n // records DB state/error, and avoids broker-forced channel close as primary failure signal.\n const brokerTimeoutMs = this.parsePositiveInt(process.env.QUEUES_RABBITMQ_CONSUMER_ACK_TIMEOUT_MS, 30 * 60 * 1000);\n\n // Soft timeout should fire *before* broker timeout so we can fail explicitly,\n // persist status/error, and avoid broker-forced channel closure as primary signal.\n // Keep at least 1s to avoid zero/negative values when broker timeout is very small.\n const defaultSoftTimeoutMs = Math.max(1_000, brokerTimeoutMs - 30_000);\n\n // Final timeout precedence:\n // 1) QUEUES_RABBITMQ_SUBSCRIBER_PROCESSING_TIMEOUT_MS (if valid positive int)\n // 2) Derived defaultSoftTimeoutMs (broker timeout - 30s)\n return this.parsePositiveInt(process.env.QUEUES_RABBITMQ_SUBSCRIBER_PROCESSING_TIMEOUT_MS, defaultSoftTimeoutMs);\n }\n\n private parsePositiveInt(value: string | undefined, fallback: number): number {\n // Shared env parsing helper:\n // - missing/invalid/non-positive => fallback\n // - valid positive integer => parsed value\n if (!value) return fallback;\n const parsed = Number.parseInt(value, 10);\n return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback;\n }\n\n private async subscribeWithTimeout(message: QueueMessage<T>, queueName: string): Promise<any> {\n const timeoutMs = this.resolveProcessingTimeoutMs();\n const messageId = message?.messageId || 'unknown';\n\n // Allow an escape hatch: non-positive timeout means run without a soft timeout.\n if (timeoutMs <= 0) {\n return this.subscribe(message);\n }\n\n let timedOut = false;\n let timeoutHandle: NodeJS.Timeout | null = null;\n\n // Main subscriber work promise.\n // If timeout has already fired, suppress rethrow to avoid unhandled rejection noise\n // (the timeout error is already the authoritative failure we track).\n const subscribePromise = Promise.resolve()\n .then(() => this.subscribe(message))\n .catch((error) => {\n if (timedOut) {\n this.logger.error(\n `Subscriber promise rejected after timeout for queue ${queueName} and messageId ${messageId}: ${(error as Error)?.message || String(error)}`,\n (error as Error)?.stack,\n );\n return undefined;\n }\n throw error;\n });\n\n // Timeout promise rejects after timeoutMs with an explicit domain-specific error.\n const timeoutPromise = new Promise<never>((_, reject) => {\n timeoutHandle = setTimeout(() => {\n timedOut = true;\n reject(new ConsumerProcessingTimeoutError(queueName, messageId, timeoutMs));\n }, timeoutMs);\n });\n\n try {\n // Promise.race settles as soon as the *first* promise settles.\n // - If subscribePromise resolves/rejects first, we use that outcome.\n // - If timeoutPromise rejects first, we fail fast with timeout error.\n // This ensures we mark DB status via normal error handling before broker ack-timeout.\n return await Promise.race([subscribePromise, timeoutPromise]);\n } catch (error) {\n const errorMessage = (error as Error)?.message || String(error);\n this.logger.error(\n `Subscriber execution failed for queue ${queueName} and messageId ${messageId}: ${errorMessage}`,\n (error as Error)?.stack,\n );\n throw error;\n } finally {\n // Always clear timer once race settles to avoid timer leaks.\n if (timeoutHandle) {\n clearTimeout(timeoutHandle);\n }\n }\n }\n\n}\n"]}
@@ -12,7 +12,7 @@ export declare abstract class RedisSubscriber<T> implements OnModuleInit, OnModu
12
12
  private reconnectAttempt;
13
13
  private stopping;
14
14
  constructor(mqMessageService: MqMessageService, mqMessageQueueService: MqMessageQueueService);
15
- abstract subscribe(message: QueueMessage<T>): void;
15
+ abstract subscribe(message: QueueMessage<T>): Promise<any>;
16
16
  abstract options(): QueuesModuleOptions;
17
17
  onModuleInit(): Promise<void>;
18
18
  onModuleDestroy(): Promise<void>;
@@ -1 +1 @@
1
- {"version":3,"file":"redis-subscriber.service.d.ts","sourceRoot":"","sources":["../../../src/services/queues/redis-subscriber.service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAU,eAAe,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAEvE,OAAO,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AACpE,OAAO,EAAE,qBAAqB,EAAE,MAAM,6BAA6B,CAAC;AACpE,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAGzD,8BAAsB,eAAe,CAAC,CAAC,CAAE,YAAW,YAAY,EAAE,eAAe,EAAE,eAAe,CAAC,CAAC,CAAC;IAQ7F,SAAS,CAAC,QAAQ,CAAC,gBAAgB,EAAE,gBAAgB;IACrD,SAAS,CAAC,QAAQ,CAAC,qBAAqB,EAAE,qBAAqB;IARnE,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAoC;IAC3D,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,MAAM,CAAsB;IACpC,OAAO,CAAC,gBAAgB,CAAK;IAC7B,OAAO,CAAC,QAAQ,CAAS;gBAGF,gBAAgB,EAAE,gBAAgB,EAClC,qBAAqB,EAAE,qBAAqB;IAQnE,QAAQ,CAAC,SAAS,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC,CAAC,GAAG,IAAI;IAElD,QAAQ,CAAC,OAAO,IAAI,mBAAmB;IAEjC,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC;IAqC7B,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC;YAKxB,mBAAmB;YA2CnB,qBAAqB;IAuBnC,OAAO,CAAC,gBAAgB;YAkBV,OAAO;IAarB,OAAO,CAAC,OAAO;cAQC,cAAc,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;YAMzD,sBAAsB;CAyBvC"}
1
+ {"version":3,"file":"redis-subscriber.service.d.ts","sourceRoot":"","sources":["../../../src/services/queues/redis-subscriber.service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAU,eAAe,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAEvE,OAAO,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AACpE,OAAO,EAAE,qBAAqB,EAAE,MAAM,6BAA6B,CAAC;AACpE,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAGzD,8BAAsB,eAAe,CAAC,CAAC,CAAE,YAAW,YAAY,EAAE,eAAe,EAAE,eAAe,CAAC,CAAC,CAAC;IAQ7F,SAAS,CAAC,QAAQ,CAAC,gBAAgB,EAAE,gBAAgB;IACrD,SAAS,CAAC,QAAQ,CAAC,qBAAqB,EAAE,qBAAqB;IARnE,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAoC;IAC3D,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,MAAM,CAAsB;IACpC,OAAO,CAAC,gBAAgB,CAAK;IAC7B,OAAO,CAAC,QAAQ,CAAS;gBAGF,gBAAgB,EAAE,gBAAgB,EAClC,qBAAqB,EAAE,qBAAqB;IAQnE,QAAQ,CAAC,SAAS,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC;IAE1D,QAAQ,CAAC,OAAO,IAAI,mBAAmB;IAEjC,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC;IAqC7B,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC;YAKxB,mBAAmB;YA2CnB,qBAAqB;IAuBnC,OAAO,CAAC,gBAAgB;YAkBV,OAAO;IAarB,OAAO,CAAC,OAAO;cAQC,cAAc,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;YAMzD,sBAAsB;CAyBvC"}
@@ -1 +1 @@
1
- {"version":3,"file":"redis-subscriber.service.js","sourceRoot":"","sources":["../../../src/services/queues/redis-subscriber.service.ts"],"names":[],"mappings":"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","sourcesContent":["import { Logger, OnModuleDestroy, OnModuleInit } from '@nestjs/common';\nimport Redis from 'ioredis';\nimport { QueuesModuleOptions } from '../../interfaces';\nimport { QueueMessage, QueueSubscriber } from '../../interfaces/mq';\nimport { MqMessageQueueService } from '../mq-message-queue.service';\nimport { MqMessageService } from '../mq-message.service';\nimport { buildNamespacedQueueName } from './common';\n\nexport abstract class RedisSubscriber<T> implements OnModuleInit, OnModuleDestroy, QueueSubscriber<T> {\n private readonly logger = new Logger(RedisSubscriber.name);\n private readonly serviceRole: string;\n private client: Redis | null = null;\n private reconnectAttempt = 0;\n private stopping = false;\n\n constructor(\n protected readonly mqMessageService: MqMessageService,\n protected readonly mqMessageQueueService: MqMessageQueueService,\n ) {\n this.serviceRole = process.env.QUEUES_SERVICE_ROLE;\n if (!process.env.QUEUES_REDIS_URL) {\n this.logger.debug('RedisSubscriber: QUEUES_REDIS_URL is not defined in the environment variables');\n }\n }\n\n abstract subscribe(message: QueueMessage<T>): void;\n\n abstract options(): QueuesModuleOptions;\n\n async onModuleInit(): Promise<void> {\n const defaultBroker = process.env.QUEUES_DEFAULT_BROKER || 'database';\n const solidCliRunning = process.env.SOLID_CLI_RUNNING || 'false';\n const queueNameRegex = (process.env.QUEUES_QUEUE_NAME_REGEX_TO_ENABLE || '').trim();\n\n if (\n process.env.QUEUES_REDIS_URL &&\n ['both', 'subscriber'].includes(this.serviceRole) &&\n solidCliRunning === 'false' &&\n defaultBroker === 'redis'\n ) {\n const options = this.options();\n const queueName = options.queueName;\n\n if (queueNameRegex && queueNameRegex !== 'all') {\n try {\n const regex = new RegExp(queueNameRegex);\n if (!regex.test(queueName)) {\n this.logger.log(\n `RedisSubscriber for queue ${queueName} is disabled because it does not match QUEUES_QUEUE_NAME_REGEX_TO_ENABLE=${queueNameRegex}`,\n );\n return;\n }\n } catch (error) {\n this.logger.error(\n `Invalid QUEUES_QUEUE_NAME_REGEX_TO_ENABLE regex \"${queueNameRegex}\". Subscriber for queue ${queueName} will not start.`,\n );\n return;\n }\n }\n\n const namespacedQueueName = buildNamespacedQueueName(queueName);\n await this.connectAndSubscribe(namespacedQueueName);\n this.logger.log(`RedisSubscriber ready to consume messages: ${JSON.stringify(options)}`);\n }\n }\n\n async onModuleDestroy(): Promise<void> {\n this.stopping = true;\n await this.cleanup();\n }\n\n private async connectAndSubscribe(channel: string): Promise<void> {\n await this.cleanup();\n\n const client = new Redis(process.env.QUEUES_REDIS_URL);\n this.client = client;\n\n client.on('error', (err) => {\n if (client !== this.client) return;\n this.logger.error(`RedisSubscriber connection error for channel ${channel}: ${err.message}`, err.stack);\n });\n\n client.on('close', () => {\n if (client !== this.client) return;\n this.logger.warn(`RedisSubscriber connection closed for channel ${channel}`);\n this.triggerReconnect(channel, 'connection closed');\n });\n\n client.on('message', async (receivedChannel, rawMessage) => {\n if (receivedChannel !== channel) return;\n\n let message: QueueMessage<T> = null;\n try {\n message = JSON.parse(rawMessage) as QueueMessage<T>;\n } catch (error) {\n this.logger.error(`RedisSubscriber invalid JSON on channel ${channel}: ${(error as Error).message}`);\n return;\n }\n\n if (!message.retryCount) message.retryCount = 0;\n if (!message.retryInterval) message.retryInterval = 1000;\n if (!message.currentRetry) message.currentRetry = 0;\n\n try {\n await this.processMessage(message);\n } catch (error) {\n await this.handleProcessingError(message, error, channel);\n }\n });\n\n await client.subscribe(channel);\n this.reconnectAttempt = 0;\n }\n\n private async handleProcessingError(message: QueueMessage<T>, error: any, channel: string): Promise<void> {\n const errorMessage = (error as Error)?.message || String(error);\n this.logger.error(`Error processing message on channel ${channel}: ${errorMessage}`);\n\n if (message.currentRetry < message.retryCount) {\n await this.updateStatusInDatabase('retrying', message);\n message.currentRetry++;\n this.logger.warn(\n `Retrying message (${message.currentRetry}/${message.retryCount}) after ${message.retryInterval}ms on channel ${channel}`,\n );\n setTimeout(async () => {\n try {\n await this.processMessage(message);\n } catch (retryError) {\n await this.handleProcessingError(message, retryError, channel);\n }\n }, message.retryInterval);\n } else {\n await this.updateStatusInDatabase('failed', message, errorMessage, '');\n this.logger.error(`Message failed after ${message.retryCount} attempts on channel ${channel}: ${errorMessage}`);\n }\n }\n\n private triggerReconnect(channel: string, reason: string): void {\n if (this.stopping) return;\n\n this.reconnectAttempt++;\n const delay = this.backoff();\n this.logger.warn(`RedisSubscriber reconnecting for channel ${channel} (${reason}) in ${delay}ms`);\n\n setTimeout(async () => {\n if (this.stopping) return;\n try {\n await this.connectAndSubscribe(channel);\n this.logger.log(`RedisSubscriber reconnected for channel ${channel}`);\n } catch (err) {\n this.triggerReconnect(channel, `reconnect failed: ${(err as Error).message}`);\n }\n }, delay);\n }\n\n private async cleanup(): Promise<void> {\n const client = this.client;\n this.client = null;\n\n if (client) {\n try {\n await client.quit();\n } catch (_) {\n // ignore\n }\n }\n }\n\n private backoff(): number {\n const baseMs = 1000;\n const maxMs = 30_000;\n const exp = Math.min(maxMs, baseMs * Math.pow(2, this.reconnectAttempt));\n const jitter = Math.floor(Math.random() * (exp * 0.2));\n return Math.min(maxMs, exp + jitter);\n }\n\n protected async processMessage(message: QueueMessage<T>): Promise<void> {\n await this.updateStatusInDatabase('started', message);\n const result: any = await (this.subscribe(message) as any);\n await this.updateStatusInDatabase('succeeded', message, '', result != null ? JSON.stringify(result, null, 2) : '');\n }\n\n private async updateStatusInDatabase(\n stage: string,\n message: QueueMessage<T>,\n error: string = '',\n result: string = '',\n ): Promise<void> {\n try {\n const mqMessage = await this.mqMessageService.repo.findOne({\n where: { messageId: message.messageId },\n });\n\n if (mqMessage) {\n const updatedFields: Record<string, any> = { stage };\n if (stage === 'failed' || stage === 'succeeded') {\n updatedFields['finishedAt'] = new Date();\n updatedFields['elapsedMillis'] = updatedFields['finishedAt'].getTime() - mqMessage.startedAt.getTime();\n }\n if (stage === 'succeeded') updatedFields['output'] = result;\n if (stage === 'failed') updatedFields['error'] = error;\n await this.mqMessageService.repo.update(mqMessage.id, updatedFields);\n }\n } catch (err) {\n this.logger.error(err.message, err.stack);\n }\n }\n}"]}
1
+ {"version":3,"file":"redis-subscriber.service.js","sourceRoot":"","sources":["../../../src/services/queues/redis-subscriber.service.ts"],"names":[],"mappings":"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","sourcesContent":["import { Logger, OnModuleDestroy, OnModuleInit } from '@nestjs/common';\nimport Redis from 'ioredis';\nimport { QueuesModuleOptions } from '../../interfaces';\nimport { QueueMessage, QueueSubscriber } from '../../interfaces/mq';\nimport { MqMessageQueueService } from '../mq-message-queue.service';\nimport { MqMessageService } from '../mq-message.service';\nimport { buildNamespacedQueueName } from './common';\n\nexport abstract class RedisSubscriber<T> implements OnModuleInit, OnModuleDestroy, QueueSubscriber<T> {\n private readonly logger = new Logger(RedisSubscriber.name);\n private readonly serviceRole: string;\n private client: Redis | null = null;\n private reconnectAttempt = 0;\n private stopping = false;\n\n constructor(\n protected readonly mqMessageService: MqMessageService,\n protected readonly mqMessageQueueService: MqMessageQueueService,\n ) {\n this.serviceRole = process.env.QUEUES_SERVICE_ROLE;\n if (!process.env.QUEUES_REDIS_URL) {\n this.logger.debug('RedisSubscriber: QUEUES_REDIS_URL is not defined in the environment variables');\n }\n }\n\n abstract subscribe(message: QueueMessage<T>): Promise<any>;\n\n abstract options(): QueuesModuleOptions;\n\n async onModuleInit(): Promise<void> {\n const defaultBroker = process.env.QUEUES_DEFAULT_BROKER || 'database';\n const solidCliRunning = process.env.SOLID_CLI_RUNNING || 'false';\n const queueNameRegex = (process.env.QUEUES_QUEUE_NAME_REGEX_TO_ENABLE || '').trim();\n\n if (\n process.env.QUEUES_REDIS_URL &&\n ['both', 'subscriber'].includes(this.serviceRole) &&\n solidCliRunning === 'false' &&\n defaultBroker === 'redis'\n ) {\n const options = this.options();\n const queueName = options.queueName;\n\n if (queueNameRegex && queueNameRegex !== 'all') {\n try {\n const regex = new RegExp(queueNameRegex);\n if (!regex.test(queueName)) {\n this.logger.log(\n `RedisSubscriber for queue ${queueName} is disabled because it does not match QUEUES_QUEUE_NAME_REGEX_TO_ENABLE=${queueNameRegex}`,\n );\n return;\n }\n } catch (error) {\n this.logger.error(\n `Invalid QUEUES_QUEUE_NAME_REGEX_TO_ENABLE regex \"${queueNameRegex}\". Subscriber for queue ${queueName} will not start.`,\n );\n return;\n }\n }\n\n const namespacedQueueName = buildNamespacedQueueName(queueName);\n await this.connectAndSubscribe(namespacedQueueName);\n this.logger.log(`RedisSubscriber ready to consume messages: ${JSON.stringify(options)}`);\n }\n }\n\n async onModuleDestroy(): Promise<void> {\n this.stopping = true;\n await this.cleanup();\n }\n\n private async connectAndSubscribe(channel: string): Promise<void> {\n await this.cleanup();\n\n const client = new Redis(process.env.QUEUES_REDIS_URL);\n this.client = client;\n\n client.on('error', (err) => {\n if (client !== this.client) return;\n this.logger.error(`RedisSubscriber connection error for channel ${channel}: ${err.message}`, err.stack);\n });\n\n client.on('close', () => {\n if (client !== this.client) return;\n this.logger.warn(`RedisSubscriber connection closed for channel ${channel}`);\n this.triggerReconnect(channel, 'connection closed');\n });\n\n client.on('message', async (receivedChannel, rawMessage) => {\n if (receivedChannel !== channel) return;\n\n let message: QueueMessage<T> = null;\n try {\n message = JSON.parse(rawMessage) as QueueMessage<T>;\n } catch (error) {\n this.logger.error(`RedisSubscriber invalid JSON on channel ${channel}: ${(error as Error).message}`);\n return;\n }\n\n if (!message.retryCount) message.retryCount = 0;\n if (!message.retryInterval) message.retryInterval = 1000;\n if (!message.currentRetry) message.currentRetry = 0;\n\n try {\n await this.processMessage(message);\n } catch (error) {\n await this.handleProcessingError(message, error, channel);\n }\n });\n\n await client.subscribe(channel);\n this.reconnectAttempt = 0;\n }\n\n private async handleProcessingError(message: QueueMessage<T>, error: any, channel: string): Promise<void> {\n const errorMessage = (error as Error)?.message || String(error);\n this.logger.error(`Error processing message on channel ${channel}: ${errorMessage}`);\n\n if (message.currentRetry < message.retryCount) {\n await this.updateStatusInDatabase('retrying', message);\n message.currentRetry++;\n this.logger.warn(\n `Retrying message (${message.currentRetry}/${message.retryCount}) after ${message.retryInterval}ms on channel ${channel}`,\n );\n setTimeout(async () => {\n try {\n await this.processMessage(message);\n } catch (retryError) {\n await this.handleProcessingError(message, retryError, channel);\n }\n }, message.retryInterval);\n } else {\n await this.updateStatusInDatabase('failed', message, errorMessage, '');\n this.logger.error(`Message failed after ${message.retryCount} attempts on channel ${channel}: ${errorMessage}`);\n }\n }\n\n private triggerReconnect(channel: string, reason: string): void {\n if (this.stopping) return;\n\n this.reconnectAttempt++;\n const delay = this.backoff();\n this.logger.warn(`RedisSubscriber reconnecting for channel ${channel} (${reason}) in ${delay}ms`);\n\n setTimeout(async () => {\n if (this.stopping) return;\n try {\n await this.connectAndSubscribe(channel);\n this.logger.log(`RedisSubscriber reconnected for channel ${channel}`);\n } catch (err) {\n this.triggerReconnect(channel, `reconnect failed: ${(err as Error).message}`);\n }\n }, delay);\n }\n\n private async cleanup(): Promise<void> {\n const client = this.client;\n this.client = null;\n\n if (client) {\n try {\n await client.quit();\n } catch (_) {\n // ignore\n }\n }\n }\n\n private backoff(): number {\n const baseMs = 1000;\n const maxMs = 30_000;\n const exp = Math.min(maxMs, baseMs * Math.pow(2, this.reconnectAttempt));\n const jitter = Math.floor(Math.random() * (exp * 0.2));\n return Math.min(maxMs, exp + jitter);\n }\n\n protected async processMessage(message: QueueMessage<T>): Promise<void> {\n await this.updateStatusInDatabase('started', message);\n const result: any = await (this.subscribe(message) as any);\n await this.updateStatusInDatabase('succeeded', message, '', result != null ? JSON.stringify(result, null, 2) : '');\n }\n\n private async updateStatusInDatabase(\n stage: string,\n message: QueueMessage<T>,\n error: string = '',\n result: string = '',\n ): Promise<void> {\n try {\n const mqMessage = await this.mqMessageService.repo.findOne({\n where: { messageId: message.messageId },\n });\n\n if (mqMessage) {\n const updatedFields: Record<string, any> = { stage };\n if (stage === 'failed' || stage === 'succeeded') {\n updatedFields['finishedAt'] = new Date();\n updatedFields['elapsedMillis'] = updatedFields['finishedAt'].getTime() - mqMessage.startedAt.getTime();\n }\n if (stage === 'succeeded') updatedFields['output'] = result;\n if (stage === 'failed') updatedFields['error'] = error;\n await this.mqMessageService.repo.update(mqMessage.id, updatedFields);\n }\n } catch (err) {\n this.logger.error(err.message, err.stack);\n }\n }\n}\n"]}
@@ -52,7 +52,7 @@ const nest_winston_1 = require("nest-winston");
52
52
  const winston = __importStar(require("winston"));
53
53
  const disallow_in_production_decorator_1 = require("./decorators/disallow-in-production.decorator");
54
54
  exports.WinstonLoggerConfig = {
55
- level: process.env.LOG_LEVEL || (process.env.ENV === disallow_in_production_decorator_1.Environment.Production ? 'warn' : 'debug'),
55
+ level: process.env.LOG_LEVEL || (process.env.ENV === disallow_in_production_decorator_1.Environment.Production ? 'info' : 'debug'),
56
56
  format: winston.format.combine(winston.format.timestamp(), winston.format.errors({ stack: true }), winston.format.printf(({ level, message, timestamp }) => {
57
57
  if (!message) {
58
58
  return `[${timestamp}] ${level.toUpperCase()}: (No message provided)`;
@@ -1 +1 @@
1
- {"version":3,"file":"winston.logger.js","sourceRoot":"","sources":["../src/winston.logger.ts"],"names":[],"mappings":"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","sourcesContent":["\nimport { Logger as TypeORMLogger, QueryRunner } from 'typeorm';\nimport { Logger } from 'winston';\nimport { Inject } from '@nestjs/common';\nimport { WINSTON_MODULE_PROVIDER } from 'nest-winston';\nimport * as winston from 'winston';\nimport { Environment } from './decorators/disallow-in-production.decorator';\n\nexport const WinstonLoggerConfig = {\n level: process.env.LOG_LEVEL || (process.env.ENV === Environment.Production ? 'warn' : 'debug'),\n format: winston.format.combine(\n winston.format.timestamp(),\n winston.format.errors({ stack: true }),\n winston.format.printf(({ level, message, timestamp }) => {\n if (!message) {\n return `[${timestamp}] ${level.toUpperCase()}: (No message provided)`;\n }\n return `[${timestamp}] ${level.toUpperCase()}: ${message}`;\n }),\n ),\n transports: [\n new winston.transports.Console({\n format: winston.format.combine(\n // winston.format.colorize(),\n // winston.format.timestamp(),\n winston.format.printf(({ level, message, timestamp }) => {\n return `[${timestamp}] ${level.toUpperCase()}: ${message}`;\n }),\n ),\n }),\n new winston.transports.File({\n filename: 'logs/application.log',\n // format: winston.format.json(),\n }),\n new winston.transports.File({\n filename: 'logs/error.log',\n level: 'error',\n // format: winston.format.json(),\n }),\n ],\n};\n\nexport class WinstonTypeORMLogger implements TypeORMLogger {\n constructor(@Inject(WINSTON_MODULE_PROVIDER) private readonly logger: Logger) { }\n\n logQuery(query: string, parameters?: any[], queryRunner?: QueryRunner): void {\n if (Boolean(process.env.DEFAULT_DATABASE_LOGGING)) {\n this.logger.info(`Query: ${query} Parameters: ${parameters}`);\n }\n }\n\n logQueryError(error: string, query: string, parameters?: any[], queryRunner?: QueryRunner): void {\n this.logger.error(`Query failed: ${error} | Query: ${query} | Parameters: ${parameters}`);\n }\n\n logQuerySlow(time: number, query: string, parameters?: any[], queryRunner?: QueryRunner): void {\n this.logger.warn(`Slow query: ${time}ms | Query: ${query} | Parameters: ${parameters}`);\n }\n\n logSchemaBuild(message: string, queryRunner?: QueryRunner): void {\n this.logger.info(`Schema Build: ${message}`);\n }\n\n logMigration(message: string, queryRunner?: QueryRunner): void {\n this.logger.info(`Migration: ${message}`);\n }\n\n log(level: 'log' | 'info' | 'warn' | 'error', message: any): void {\n this.logger[level](message);\n }\n}"]}
1
+ {"version":3,"file":"winston.logger.js","sourceRoot":"","sources":["../src/winston.logger.ts"],"names":[],"mappings":"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","sourcesContent":["\nimport { Logger as TypeORMLogger, QueryRunner } from 'typeorm';\nimport { Logger } from 'winston';\nimport { Inject } from '@nestjs/common';\nimport { WINSTON_MODULE_PROVIDER } from 'nest-winston';\nimport * as winston from 'winston';\nimport { Environment } from './decorators/disallow-in-production.decorator';\n\nexport const WinstonLoggerConfig = {\n level: process.env.LOG_LEVEL || (process.env.ENV === Environment.Production ? 'info' : 'debug'),\n format: winston.format.combine(\n winston.format.timestamp(),\n winston.format.errors({ stack: true }),\n winston.format.printf(({ level, message, timestamp }) => {\n if (!message) {\n return `[${timestamp}] ${level.toUpperCase()}: (No message provided)`;\n }\n return `[${timestamp}] ${level.toUpperCase()}: ${message}`;\n }),\n ),\n transports: [\n new winston.transports.Console({\n format: winston.format.combine(\n // winston.format.colorize(),\n // winston.format.timestamp(),\n winston.format.printf(({ level, message, timestamp }) => {\n return `[${timestamp}] ${level.toUpperCase()}: ${message}`;\n }),\n ),\n }),\n new winston.transports.File({\n filename: 'logs/application.log',\n // format: winston.format.json(),\n }),\n new winston.transports.File({\n filename: 'logs/error.log',\n level: 'error',\n // format: winston.format.json(),\n }),\n ],\n};\n\nexport class WinstonTypeORMLogger implements TypeORMLogger {\n constructor(@Inject(WINSTON_MODULE_PROVIDER) private readonly logger: Logger) { }\n\n logQuery(query: string, parameters?: any[], queryRunner?: QueryRunner): void {\n if (Boolean(process.env.DEFAULT_DATABASE_LOGGING)) {\n this.logger.info(`Query: ${query} Parameters: ${parameters}`);\n }\n }\n\n logQueryError(error: string, query: string, parameters?: any[], queryRunner?: QueryRunner): void {\n this.logger.error(`Query failed: ${error} | Query: ${query} | Parameters: ${parameters}`);\n }\n\n logQuerySlow(time: number, query: string, parameters?: any[], queryRunner?: QueryRunner): void {\n this.logger.warn(`Slow query: ${time}ms | Query: ${query} | Parameters: ${parameters}`);\n }\n\n logSchemaBuild(message: string, queryRunner?: QueryRunner): void {\n this.logger.info(`Schema Build: ${message}`);\n }\n\n logMigration(message: string, queryRunner?: QueryRunner): void {\n this.logger.info(`Migration: ${message}`);\n }\n\n log(level: 'log' | 'info' | 'warn' | 'error', message: any): void {\n this.logger[level](message);\n }\n}"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@solidxai/core",
3
- "version": "0.1.9-beta.5",
3
+ "version": "0.1.9-beta.6",
4
4
  "description": "This module is a NestJS module containing all the required core providers required by a Solid application",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -6,8 +6,9 @@ import helmet from 'helmet';
6
6
  import qs from 'qs';
7
7
  import { existsSync } from 'fs';
8
8
  import { resolve } from 'path';
9
- import { WINSTON_MODULE_NEST_PROVIDER } from 'nest-winston';
9
+ import { WINSTON_MODULE_NEST_PROVIDER, WinstonModule } from 'nest-winston';
10
10
  import { CommandFactory } from 'nest-commander';
11
+ import { WinstonLoggerConfig } from '../winston.logger';
11
12
  import { WrapResponseInterceptor } from '../interceptors/wrap-response.interceptor';
12
13
  import { buildDefaultCorsOptions } from './cors.helper';
13
14
  import { buildDefaultSecurityHeaderOptions, buildPermissionsPolicyHeader, PermissionsPolicyConfig } from './security.helper';
@@ -71,7 +72,9 @@ export async function bootstrapSolidApp(
71
72
  const { globalPrefix = 'api', swagger = {}, permissionsPolicyOverrides = {} } = options;
72
73
 
73
74
  const appModule = await appModuleFactory();
74
- const app = await NestFactory.create(appModule);
75
+ const app = await NestFactory.create(appModule, {
76
+ logger: WinstonModule.createLogger(WinstonLoggerConfig),
77
+ });
75
78
 
76
79
  const apiEnabled = parseBooleanEnv('API_ENABLED', true);
77
80
 
@@ -19,5 +19,5 @@ export interface QueuePublisher<T> {
19
19
 
20
20
  export interface QueueSubscriber<T> {
21
21
  options(): QueuesModuleOptions;
22
- subscribe(message: QueueMessage<T>): void;
23
- }
22
+ subscribe(message: QueueMessage<T>): Promise<any>;
23
+ }
@@ -27,6 +27,6 @@ export class ApiEmailQueueSubscriberDatabase extends DatabaseSubscriber<any> {
27
27
  }
28
28
 
29
29
  subscribe(message: QueueMessage<any>) {
30
- this.emailService.sendEmailSynchronously(message);
30
+ return this.emailService.sendEmailSynchronously(message);
31
31
  }
32
32
  }
@@ -27,6 +27,6 @@ export class Msg91WhatsappQueueSubscriberDatabase extends DatabaseSubscriber<any
27
27
  }
28
28
 
29
29
  subscribe(message: QueueMessage<any>) {
30
- this.whatsappService.sendWhatsAppMessageSynchronously(message);
30
+ return this.whatsappService.sendWhatsAppMessageSynchronously(message);
31
31
  }
32
32
  }
@@ -27,6 +27,6 @@ export class Three60WhatsappQueueSubscriberDatabase extends DatabaseSubscriber<a
27
27
  }
28
28
 
29
29
  subscribe(message: QueueMessage<any>) {
30
- this.whatsappService.sendWhatsAppMessageSynchronously(message);
30
+ return this.whatsappService.sendWhatsAppMessageSynchronously(message);
31
31
  }
32
32
  }
@@ -25,6 +25,6 @@ export class ApiEmailQueueSubscriber extends RabbitMqSubscriber<any> {
25
25
  }
26
26
 
27
27
  subscribe(message: QueueMessage<any>) {
28
- this.emailService.sendEmailSynchronously(message);
28
+ return this.emailService.sendEmailSynchronously(message);
29
29
  }
30
30
  }
@@ -25,6 +25,6 @@ export class Msg91WhatsappQueueSubscriber extends RabbitMqSubscriber<any> {
25
25
  }
26
26
 
27
27
  subscribe(message: QueueMessage<any>) {
28
- this.whatsappService.sendWhatsAppMessageSynchronously(message);
28
+ return this.whatsappService.sendWhatsAppMessageSynchronously(message);
29
29
  }
30
30
  }
@@ -35,12 +35,11 @@ export class TestQueueSubscriber extends RabbitMqSubscriber<any> {
35
35
 
36
36
  this.testQueueLogger.debug(`Processing message with timeout: ${timeoutSecondsParsed}`);
37
37
 
38
- // Simulate some processing time
39
- setTimeout(() => {
40
- this.testQueueLogger.debug(`Processed message: ${JSON.stringify(message)}`);
41
- // resolve({ status: 'success', messageId: message.messageId, message: `Processed message` });
42
- }, timeoutSecondsParsed * 1000);
43
-
44
- // return new Promise((resolve, reject) => {});
38
+ return new Promise((resolve) => {
39
+ setTimeout(() => {
40
+ this.testQueueLogger.debug(`Processed message: ${JSON.stringify(message)}`);
41
+ resolve({ status: 'success', messageId: message.messageId, message: 'Processed message' });
42
+ }, timeoutSecondsParsed * 1000);
43
+ });
45
44
  }
46
45
  }
@@ -25,6 +25,6 @@ export class Three60WhatsappQueueSubscriber extends RabbitMqSubscriber<any> {
25
25
  }
26
26
 
27
27
  subscribe(message: QueueMessage<any>) {
28
- this.whatsappService.sendWhatsAppMessageSynchronously(message);
28
+ return this.whatsappService.sendWhatsAppMessageSynchronously(message);
29
29
  }
30
30
  }
@@ -25,6 +25,6 @@ export class ApiEmailQueueSubscriberRedis extends RedisSubscriber<any> {
25
25
  }
26
26
 
27
27
  subscribe(message: QueueMessage<any>) {
28
- this.emailService.sendEmailSynchronously(message);
28
+ return this.emailService.sendEmailSynchronously(message);
29
29
  }
30
30
  }
@@ -25,6 +25,6 @@ export class Msg91WhatsappQueueSubscriberRedis extends RedisSubscriber<any> {
25
25
  }
26
26
 
27
27
  subscribe(message: QueueMessage<any>) {
28
- this.whatsappService.sendWhatsAppMessageSynchronously(message);
28
+ return this.whatsappService.sendWhatsAppMessageSynchronously(message);
29
29
  }
30
30
  }
@@ -25,6 +25,6 @@ export class Three60WhatsappQueueSubscriberRedis extends RedisSubscriber<any> {
25
25
  }
26
26
 
27
27
  subscribe(message: QueueMessage<any>) {
28
- this.whatsappService.sendWhatsAppMessageSynchronously(message);
28
+ return this.whatsappService.sendWhatsAppMessageSynchronously(message);
29
29
  }
30
30
  }