@platform-x/hep-message-broker-client 1.0.2 → 1.1.3

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/README.md +1 -1
  2. package/dist/src/Util/commonUtil.js.map +1 -0
  3. package/dist/src/Util/constants.js +8 -0
  4. package/dist/src/Util/constants.js.map +1 -0
  5. package/dist/src/Util/logger.js.map +1 -0
  6. package/dist/src/Util/requestTracer.js.map +1 -0
  7. package/dist/src/config/ConfigManager.js.map +1 -0
  8. package/dist/src/config/index.js +1 -1
  9. package/dist/src/config/index.js.map +1 -0
  10. package/dist/src/index.js +22 -1
  11. package/dist/src/index.js.map +1 -0
  12. package/dist/src/messageBroker/BaseRabbitMQClient.js.map +1 -0
  13. package/dist/src/messageBroker/ConnectionManager.js.map +1 -0
  14. package/dist/src/messageBroker/MessageBrokerClient.js.map +1 -0
  15. package/dist/src/messageBroker/MessageConsumer.js.map +1 -0
  16. package/dist/src/messageBroker/MessageProducer.js.map +1 -0
  17. package/dist/src/messageBroker/RabbitMQClient.js.map +1 -0
  18. package/dist/src/messageBroker/RetryManager.js.map +1 -0
  19. package/dist/src/messageBroker/interface/ConnectionWrapper.js.map +1 -0
  20. package/dist/src/messageBroker/interface/IMessageBrokerClient.js.map +1 -0
  21. package/dist/src/messageBroker/rabbitmq/MessageBrokerClient.js +5 -1
  22. package/dist/src/messageBroker/rabbitmq/MessageBrokerClient.js.map +1 -0
  23. package/dist/src/messageBroker/types/ActionType.js.map +1 -0
  24. package/dist/src/messageBroker/types/PublishMessageInputType.js.map +1 -0
  25. package/dist/src/models/MessageModel.js.map +1 -0
  26. package/dist/src/models/NotificationMessageModel.js.map +1 -0
  27. package/package.json +43 -40
  28. package/src/Util/commonUtil.ts +41 -0
  29. package/src/Util/constants.ts +4 -0
  30. package/src/Util/logger.ts +219 -0
  31. package/src/Util/requestTracer.ts +28 -0
  32. package/src/config/ConfigManager.ts +35 -0
  33. package/src/config/index.ts +31 -0
  34. package/src/index.ts +73 -0
  35. package/src/messageBroker/BaseRabbitMQClient.ts +30 -0
  36. package/src/messageBroker/ConnectionManager.ts +182 -0
  37. package/src/messageBroker/MessageBrokerClient.ts +88 -0
  38. package/src/messageBroker/MessageConsumer.ts +85 -0
  39. package/src/messageBroker/MessageProducer.ts +142 -0
  40. package/src/messageBroker/RabbitMQClient.ts +47 -0
  41. package/src/messageBroker/RetryManager.ts +64 -0
  42. package/src/messageBroker/interface/ConnectionWrapper.ts +7 -0
  43. package/src/messageBroker/interface/IMessageBrokerClient.ts +11 -0
  44. package/src/messageBroker/rabbitmq/MessageBrokerClient.ts +681 -0
  45. package/src/messageBroker/types/ActionType.ts +1 -0
  46. package/src/messageBroker/types/PublishMessageInputType.ts +8 -0
  47. package/src/models/MessageModel.ts +14 -0
  48. package/tsconfig.json +73 -0
  49. package/dist/src/Util/commonUtil.d.ts +0 -16
  50. package/dist/src/Util/logger.d.ts +0 -68
  51. package/dist/src/Util/requestTracer.d.ts +0 -7
  52. package/dist/src/config/ConfigManager.d.ts +0 -9
  53. package/dist/src/config/index.d.ts +0 -29
  54. package/dist/src/index.d.ts +0 -2
  55. package/dist/src/messageBroker/BaseRabbitMQClient.d.ts +0 -16
  56. package/dist/src/messageBroker/ConnectionManager.d.ts +0 -60
  57. package/dist/src/messageBroker/MessageBrokerClient.d.ts +0 -34
  58. package/dist/src/messageBroker/MessageConsumer.d.ts +0 -26
  59. package/dist/src/messageBroker/MessageProducer.d.ts +0 -29
  60. package/dist/src/messageBroker/RabbitMQClient.d.ts +0 -12
  61. package/dist/src/messageBroker/RetryManager.d.ts +0 -23
  62. package/dist/src/messageBroker/interface/ConnectionWrapper.d.ts +0 -6
  63. package/dist/src/messageBroker/interface/IMessageBrokerClient.d.ts +0 -7
  64. package/dist/src/messageBroker/rabbitmq/MessageBrokerClient.d.ts +0 -122
  65. package/dist/src/messageBroker/types/ActionType.d.ts +0 -1
  66. package/dist/src/messageBroker/types/PublishMessageInputType.d.ts +0 -7
  67. package/dist/src/models/MessageModel.d.ts +0 -5
  68. /package/{dist/src/models/NotificationMessageModel.d.ts → src/models/NotificationMessageModel.ts} +0 -0
@@ -0,0 +1,35 @@
1
+ import * as fs from "fs";
2
+ import config from "./index";
3
+ import { Logger } from '../Util/logger';
4
+
5
+ class ConfigManager {
6
+ private static instance: ConfigManager;
7
+ private config: any;
8
+ private constructor() {
9
+ this.config = {};
10
+ this.loadConfig(config.RABBITMQ.CONFIG_PATH);
11
+ }
12
+
13
+ public static getInstance(): ConfigManager {
14
+ if (!ConfigManager.instance) {
15
+ ConfigManager.instance = new ConfigManager();
16
+ }
17
+ return ConfigManager.instance;
18
+ }
19
+
20
+ public loadConfig(configPath: string): void {
21
+ if (fs.existsSync(configPath)) {
22
+ // Do something
23
+ this.config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
24
+ }else{
25
+ Logger.error("Config file missing!", "loadConfig")
26
+ }
27
+
28
+ }
29
+
30
+ public getConfig(): any {
31
+ return this.config;
32
+ }
33
+ }
34
+
35
+ export default ConfigManager;
@@ -0,0 +1,31 @@
1
+ import dotenv from 'dotenv';
2
+ dotenv.config();
3
+ process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
4
+
5
+ export default {
6
+ LOG_LEVELS: ['info', 'error', 'warn', 'debug'],
7
+ NODE_ENV: 'development',
8
+ APP_NAME: 'hep-message-broker-client',
9
+ RABBITMQ: {
10
+ USER: process.env.RABBITMQ_USER??'root',
11
+ PASS: process.env.RABBITMQ_PASS??'root',
12
+ HOST: process.env.RABBITMQ_HOST??'127.0.0.1',
13
+ PORT: process.env.RABBITMQ_PORT??'5672',
14
+ MAIN_QUEUE: 'main_queue',
15
+ MAIN_EXCHANGE: 'assets_metadata_generate_exchange',
16
+ DLX_QUEUE: 'dead_letter_queue',
17
+ DLX_EXCHANGE: 'assets_dlx_exchange',
18
+ RETRY_QUEUE: 'retry_queue',
19
+ RETRY_EXCHANGE: 'assets_metadata_generate_retry_exchange',
20
+ MAX_RETRIES: Number(process.env.RABBITMQ_MAX_RETRIES?.trim() ?? 1),
21
+ HEARTBEAT: Number(process.env.RABBITMQ_HEARTBEAT?.trim() ?? 5),
22
+ TTL:process.env.RABBITMQ_TTL??"3000|6000|9000",
23
+ BACKOFF_TIME:Number(process.env.BACKOFF_TIME?.trim() ?? 1000),
24
+ IS_ENABLED: process.env.RABBITMQ_IS_ENABLED ?? 'true',
25
+ RABBITMQ_CONFIG: process.env.RABBITMQ_CONFIG ?? '',
26
+ PREFETCH_COUNT: Number(process.env.RABBITMQ_PREFETCH ?? 50),
27
+ CONNECTION_ERROR:process.env.RABBITMQ_CONNECTION_ERROR ?? false,
28
+ PUBLISHER_ERROR:process.env.RABBITMQ_PUBLISHER_ERROR ?? false,
29
+ CONSUMER_ERROR:process.env.RABBITMQ_CONSUMER_ERROR ?? false,
30
+ CONFIG_PATH: process.env.CONFIG_PATH ?? '/etc/rabbitmq/rabbitMQConfig.json',
31
+ }}
package/src/index.ts ADDED
@@ -0,0 +1,73 @@
1
+
2
+ import { MessageBrokerClient } from "./messageBroker/rabbitmq/MessageBrokerClient";
3
+ // const messageBrokerClient = new MessageBrokerClient();
4
+ // let initial_message = {
5
+ // message: {
6
+ // 'queue_name': 'image_thumbnail_request_queue',
7
+ // 'body': {
8
+ // 'url': 'https://dev.dam.hcl-x.com/server/api/core/bitstreams/43817aff-ebb7-47d2-be0e-fb4db1ab267a/content',
9
+ // 'file_name': 'Kudos (1)',
10
+ // 'destination_path': '1721365841379/public/png',
11
+ // 'visibility': 'public',
12
+ // 'urgency': 0,
13
+ // 'folder_name': '',
14
+ // 'bitstream_id': '43817aff-ebb7-47d2-be0e-fb4db1ab267a',
15
+ // 'ext': 'png',
16
+ // 'asset_type': 'Image',
17
+ // 'item_id': 'b1ff157e-a04f-4f8c-83b5-3a2ead732101',
18
+ // },
19
+ // 'item_id': 'b1ff157e-a04f-4f8c-83b5-3a2ead732101',
20
+ // "language": "en",
21
+ // 'retries': 0,
22
+ // },
23
+ // corelationId: 'lgkdkfgkkfd',
24
+ // version: 0,
25
+ // trace: '',
26
+ // };
27
+
28
+ // let initial_message = {
29
+ // "message":{
30
+ // "queue_name":"summary_request_queue",
31
+ // "body":{
32
+ // "input": "€ !~!@#$%^&*()_++_<><?:{}[];,./ Hi everyone, good afternoon. Hope you all are doing good. Myself Akshima, Daitishin from Hetzial Healthcare. So today I am going to discuss about weight loss platy. We all must be aware about what is a weight loss platy. This is a term which we all come across when we are focusing on our weight loss journey. ",
33
+ // "language": "hi",
34
+ // "max_length": 20,
35
+ // "min_length": 10
36
+ // },
37
+ // "language": "en",
38
+ // "correlationId":"",
39
+ // "retries": 0
40
+ // }
41
+ // };
42
+
43
+ // console.log(initial_message)
44
+ // async function testConnection() {
45
+ // await messageBrokerClient.initialize().then(async () => {
46
+ // return '';
47
+ // setInterval(() => {
48
+ // messageBrokerClient.initializeConsumers();
49
+ // messageBrokerClient.publishMessage( { queueName: 'summary_request_queue', exchangeName:"assets_metadata_generate_exchange", message: initial_message })
50
+
51
+ // }, 1);
52
+ // });
53
+ // }
54
+
55
+ // testConnection();
56
+
57
+
58
+
59
+
60
+
61
+
62
+
63
+ export { MessageBrokerClient };
64
+ let injectedSecretService: any = null;
65
+ export const initIAMSecretsMessageBroker = (secretServiceIns: any) =>{
66
+ injectedSecretService = secretServiceIns;
67
+ }
68
+ export const getIAMSecrets = async() =>{
69
+ if (!injectedSecretService) {
70
+ throw new Error("IAM secrets not initialized");
71
+ }
72
+ return await injectedSecretService.getSecretKeys(); // returns cached data
73
+ }
@@ -0,0 +1,30 @@
1
+ import * as amqp from 'amqplib';
2
+ import ConfigManager from '../config/ConfigManager';
3
+ import config from '../config';
4
+ import ConnectionManager from './ConnectionManager';
5
+
6
+ class BaseRabbitMQClient{
7
+ public readonly configManager: ConfigManager;
8
+ public readonly connectionManager: ConnectionManager = new ConnectionManager();
9
+ protected connection: amqp.Connection | undefined;
10
+ protected channel: amqp.Channel | undefined;
11
+ protected configData: any = {};
12
+ constructor() {
13
+ this.configManager = ConfigManager.getInstance();
14
+ this.configData = this.configManager.getConfig();
15
+ this.channel = this.connectionManager.getChannel();
16
+ this.connection = this.connectionManager.getConnection();
17
+ this.init();
18
+ }
19
+
20
+ /**
21
+ * Function for load the config data
22
+ */
23
+ private init() {
24
+ this.configManager.loadConfig(config?.RABBITMQ?.CONFIG_PATH);
25
+ this.configData = this.configManager.getConfig();
26
+ }
27
+
28
+ }
29
+
30
+ export default BaseRabbitMQClient;
@@ -0,0 +1,182 @@
1
+ // Import the amqplib library for RabbitMQ
2
+ import * as amqp from 'amqplib';
3
+ import { Logger } from '../Util/logger';
4
+ import ConfigManager from '../config/ConfigManager';
5
+ import config from '../config';
6
+ let isConnectionOpen = false;
7
+ let MAX_RETRIES: number = 1;
8
+
9
+
10
+ interface ConnectionWrapper {
11
+ connection: amqp.Connection,
12
+ channel: amqp.Channel
13
+ }
14
+
15
+ class ConnectionManager {
16
+ private static instance: ConnectionManager;
17
+ private readonly configManager: ConfigManager;
18
+ protected connection: amqp.Connection | undefined;
19
+ protected channel: amqp.Channel | undefined;
20
+ protected configData: any = {};
21
+ constructor() {
22
+ this.configManager = ConfigManager.getInstance();
23
+ this.init();
24
+ }
25
+
26
+ /**
27
+ * Function for get channel
28
+ */
29
+ public getChannel():amqp.Channel | undefined{
30
+ return this.channel;
31
+ }
32
+
33
+ /**
34
+ * Function for get channel
35
+ */
36
+ public getConnection():amqp.Connection | undefined{
37
+ return this.connection;
38
+ }
39
+
40
+ /**
41
+ * Function for create and return intance
42
+ * @returns
43
+ */
44
+ public static async getInstance(): Promise<ConnectionManager> {
45
+ if (!ConnectionManager.instance) {
46
+ ConnectionManager.instance = new ConnectionManager();
47
+ }
48
+ return ConnectionManager.instance;
49
+ }
50
+
51
+ /**
52
+ * Function to connect create to RabbitMQ
53
+ */
54
+ public async createConnection(): Promise<ConnectionWrapper> {
55
+ try {
56
+ Logger.info('Reached to createConnection', 'createConnection');
57
+ this.configManager.loadConfig(config?.RABBITMQ?.CONFIG_PATH);
58
+ let url: string = `amqp://${this.configData?.username}:${this.configData?.password}@${this.configData?.host}`;
59
+ // Create a connection to RabbitMQ server
60
+ this.connection = await amqp.connect(url, { heartbeat: this.configData?.heartbeat });
61
+ isConnectionOpen = true;
62
+ // check the connection status
63
+ this.bindConnectionEventHandler();
64
+ // create channel
65
+ this.channel = await this.connection.createConfirmChannel();
66
+ Logger.info('RabbitMQ connected successfully! ', 'createConnection');
67
+ // create exchange and queue and bind with exchange
68
+ await this.setupQueuesAndExchanges();
69
+ const connectionWrapper: ConnectionWrapper = { connection: this.connection, channel: this.channel }
70
+ return connectionWrapper;
71
+ } catch (error) {
72
+ // Log and rethrow any errors that occur during connection
73
+ Logger.error('Failed to connect to RabbitMQ', 'connection', (error as Error)?.message);
74
+ return { connection: null, channel: null } as unknown as ConnectionWrapper;
75
+ }
76
+ }
77
+
78
+ /**
79
+ * Function for bind connection event handler on close and error setupQueuesAndExchanges
80
+ * @returns
81
+ */
82
+ private bindConnectionEventHandler():boolean {
83
+ try {
84
+ this.connection?.on('close', (err: any) => {
85
+ Logger.error(`RabbitMQ: bindConnectionEventHandler:close`, `Connection closed`, err);
86
+ isConnectionOpen = false;
87
+ });
88
+ this.connection?.on('error', (err: any) => {
89
+ Logger.error(`RabbitMQ: bindConnectionEventHandler:error`, `Connection error`, err);
90
+ isConnectionOpen = false;
91
+ });
92
+ return isConnectionOpen;
93
+ } catch (error) {
94
+ isConnectionOpen = false;
95
+ return isConnectionOpen;
96
+ }
97
+
98
+ }
99
+
100
+ /**
101
+ * Function to check the status of the connection
102
+ * @returns boolean
103
+ */
104
+ public async isConnected(): Promise<boolean> {
105
+ return isConnectionOpen;
106
+ };
107
+
108
+
109
+ /**
110
+ * Function to initialize the connection, channel and setup the queues and exchanges
111
+ * @param reqData
112
+ * @returns
113
+ */
114
+ public async initialize() {
115
+ Logger.info('Reached to initialize', 'initialize');
116
+ let retries: number = 0;
117
+ MAX_RETRIES = this.configData?.max_retries;
118
+ // Retrie times connection
119
+ while (retries < MAX_RETRIES) {
120
+ try {
121
+ await this.createConnection();
122
+ return { connection:this.connection, channel:this.channel };
123
+ } catch (err) {
124
+ retries++;
125
+ Logger.error('initialize:Failed to connect to RabbitMQ', `Attempt ${retries} of ${MAX_RETRIES}.`);
126
+ if (retries >= MAX_RETRIES) {
127
+ Logger.error('Max retries reached, cannot connect to RabbitMQ.', 'initialize');
128
+ return { connection:this.connection, channel:this.channel };
129
+ }
130
+ // Wait before retrying (e.g., 10 seconds)
131
+ await new Promise(resolve => setTimeout(resolve, 10000));
132
+ }
133
+ }
134
+ };
135
+
136
+ /**
137
+ * Function to setup the queues and exchanges
138
+ * @params array
139
+ * @rtrun
140
+ */
141
+ private async setupQueuesAndExchanges():Promise<void> {
142
+ Logger.info('Reached to setupQueuesAndExchanges', 'setupQueuesAndExchanges');
143
+ try {
144
+ let exchanges: any = this.configData.exchanges;
145
+ let queues: any = this.configData.queues;
146
+ let bindings: any = this.configData.bindings;
147
+ // Declare the exchange with dlx
148
+ for (let data of exchanges) {
149
+ await this.channel?.assertExchange(data?.name, data.type, { durable: data.durable, autoDelete: data.autoDelete });
150
+ Logger.info(`${data?.name} exchange created`, 'setupQueuesAndExchanges');
151
+ }
152
+
153
+ // Declare the queues with dlx
154
+ for (let data of queues) {
155
+ await this.channel?.assertQueue(data?.name, { durable: data.durable, exclusive: data.exclusive, autoDelete: data.autoDelete, arguments: data.arguments });
156
+ Logger.info(`${data?.name} queue created `, 'setupQueuesAndExchanges');
157
+ }
158
+
159
+ // Declare the bindings for queues and exchanges with routing keys
160
+ for (let obj in bindings) {
161
+ bindings[obj]?.forEach(async (key: any) => {
162
+ await this.channel?.bindQueue(key?.queue, obj, key?.routingKey);
163
+ Logger.info(`${key?.queue} bind with exchange name ${obj} and routing key ${key?.routingKey}`, 'setupQueuesAndExchanges');
164
+ })
165
+ }
166
+ } catch (error) {
167
+ Logger.error("Error on setup queues, exchanges and binding", 'setupQueuesAndExchanges', (error as Error).message);
168
+ throw error;
169
+ }
170
+ };
171
+
172
+ /**
173
+ * Function for load the config data
174
+ */
175
+ private init() {
176
+ this.configManager.loadConfig(config?.RABBITMQ?.CONFIG_PATH);
177
+ this.configData = this.configManager.getConfig();
178
+ }
179
+
180
+ }
181
+
182
+ export default ConnectionManager;
@@ -0,0 +1,88 @@
1
+ import config from '../config';
2
+ import ConfigManager from '../config/ConfigManager';
3
+ import ConnectionManager from './ConnectionManager';
4
+ import { IMessageBrokerClient } from './interface/IMessageBrokerClient';
5
+ import MessageProducer from './MessageProducer';
6
+ import { RabbitMQClient } from './RabbitMQClient';
7
+ import RetryManager from './RetryManager';
8
+ import { PublishMessageInputType } from './types/PublishMessageInputType';
9
+ const connectionManager = ConnectionManager.getInstance();
10
+ export class MessageBrokerClient implements IMessageBrokerClient {
11
+ private readonly rabbitMQClient: RabbitMQClient;
12
+ private readonly messageProducer: MessageProducer;
13
+ private readonly configManager: ConfigManager;
14
+ // private readonly retryManager: RetryManager<T>;
15
+ private readonly isEnabledRabbitMQ: boolean = false;
16
+ private readonly configData: any = {};
17
+ constructor() {
18
+ this.rabbitMQClient = new RabbitMQClient();
19
+ this.messageProducer = new MessageProducer();
20
+ this.isEnabledRabbitMQ = config?.RABBITMQ?.IS_ENABLED === 'true';
21
+ this.configManager = ConfigManager.getInstance();
22
+ this.configData = this.configManager.getConfig();
23
+ }
24
+
25
+ /**
26
+ * Function to initialize the RabbitMQ connection
27
+ */
28
+ async initialize(): Promise<void> {
29
+ if(this.isEnabledRabbitMQ){
30
+ this.rabbitMQClient.initialize();
31
+ }
32
+ }
33
+
34
+ /**
35
+ * Function to close the connection and channel
36
+ */
37
+ disconnect(): void {
38
+ if(this.isEnabledRabbitMQ){
39
+ this.rabbitMQClient.disconnect();
40
+ }
41
+ }
42
+
43
+ /**
44
+ * Function to publish a message with retry
45
+ * @param request
46
+ * @returns
47
+ */
48
+ publishMessage(request:PublishMessageInputType): Promise<boolean> {
49
+ if(this.isEnabledRabbitMQ){
50
+ const boundPublishMessage = this.messageProducer.publishMessage.bind(this);
51
+ const boundConsumerHandler = this.messageProducer.messageHandler.bind(this);
52
+ let retry_delay = this.configData?.retry_delay;
53
+ let max_retries = this.configData?.max_retries;
54
+ // Instantiate RetryManager
55
+ const retryManager = RetryManager.getInstance<PublishMessageInputType>(max_retries, retry_delay);
56
+ retryManager.performActionWithRetry(boundPublishMessage, request, boundConsumerHandler)
57
+ }
58
+ return Promise.resolve(false);
59
+ }
60
+
61
+ /**
62
+ * Function to publish a message with retry to exchange
63
+ * @param request
64
+ * @returns
65
+ */
66
+ publishMessageToExchange(request:PublishMessageInputType): Promise<boolean> {
67
+ if(this.isEnabledRabbitMQ){
68
+ const boundPublishMessage = this.messageProducer.publishMessageToExchange.bind(this);
69
+ const boundConsumerHandler = this.messageProducer.messageHandler.bind(this);
70
+ let retry_delay = this.configData?.retry_delay;
71
+ let max_retries = this.configData?.max_retries;
72
+ // Instantiate RetryManager
73
+ const retryManager = RetryManager.getInstance<PublishMessageInputType>(max_retries, retry_delay);
74
+ retryManager.performActionWithRetry(boundPublishMessage, request, boundConsumerHandler)
75
+ }
76
+ return Promise.resolve(false);
77
+ }
78
+ /***
79
+ * Function to check if the connection is established
80
+ */
81
+ async isConnected(): Promise<boolean> {
82
+ if(this.isEnabledRabbitMQ){
83
+ return (await connectionManager) ? (await connectionManager).isConnected() : Promise.resolve(false);
84
+ }
85
+ return Promise.resolve(false);
86
+ }
87
+
88
+ }
@@ -0,0 +1,85 @@
1
+ import { Logger } from "../Util/logger";
2
+ import { PublishMessageInputType } from "./types/PublishMessageInputType";
3
+ import RetryManager from './RetryManager';
4
+ import MessageProducer from "./MessageProducer";
5
+ import BaseRabbitMQClient from "./BaseRabbitMQClient";
6
+
7
+
8
+ let configData: any = {};
9
+ let max_retries: number = 0; // Maximum retries for connection and queue
10
+ let retry_delay: string = ""; // Back-off time for message retry
11
+
12
+ class MessageConsumer extends BaseRabbitMQClient{
13
+ private readonly messageProducer: MessageProducer;
14
+ constructor() {
15
+ super();
16
+ this.messageProducer = new MessageProducer()
17
+ }
18
+ /**
19
+ * Funvction for initialize consumer queue
20
+ * @param consumerQueues
21
+ */
22
+ public async initializeConsumers() {
23
+ try {
24
+ Logger.info('Reached in initialize consumer', `initializeConsumers`);
25
+ let consume_queues = configData?.consume_queues;
26
+ // Consume messages from all queues
27
+ for (const queue in configData?.consume_queues) {
28
+ if (Object.prototype.hasOwnProperty.call(consume_queues, queue)) {
29
+ // Call function Consume messages with retry
30
+ await this.consumerMessage(queue);
31
+ }
32
+ }
33
+ } catch (error: unknown) {
34
+ Logger.error('Error initializing consumers:', 'initializeConsumers', (error as Error).message);
35
+ return { error: (error as Error).message };
36
+ }
37
+ }
38
+
39
+
40
+
41
+ /**
42
+ * Function to consume message with retry
43
+ * @param queueName
44
+ */
45
+ private async consumerMessage(queueName: string) {
46
+ Logger.info("Reached: Consuming messages from the main queue", 'consumerMessage')
47
+ await this.channel?.consume(queueName, async (message: any) => {
48
+ if (message) {
49
+ let msgData: any = message.content.toString();
50
+ const success: boolean = await this.consumerHandler({ queueName, message: msgData });
51
+ try {
52
+ if (!success) {
53
+ const boundPublishMessage = this.messageProducer.publishMessage.bind(this);
54
+ const boundConsumerHandler = this.consumerHandler.bind(this);
55
+ retry_delay = configData?.retry_delay;
56
+ const reqData: PublishMessageInputType = { queueName, message };
57
+ // Instantiate RetryManager
58
+ const retryManager = RetryManager.getInstance<PublishMessageInputType>(max_retries, retry_delay);
59
+ retryManager.performActionWithRetry(boundPublishMessage, reqData, boundConsumerHandler)
60
+ } else {
61
+ Logger.info(`Acknowledge the successful processing`, 'consumerMessage');
62
+ this.channel?.ack(message); // Acknowledge the successful processing
63
+ }
64
+ } catch (error) {
65
+ Logger.error(`Error processing message`, 'consumerMessage', { message: (error as Error).message });
66
+ this.channel?.nack(message, false, false); // Move message to DLQ after failure
67
+ }
68
+ }
69
+ });
70
+ };
71
+
72
+ /**
73
+ * Function for consumer massage handler
74
+ * @param channel
75
+ * @param queue
76
+ * @param message
77
+ * @returns
78
+ */
79
+ private async consumerHandler(request: PublishMessageInputType): Promise<boolean> {
80
+ Logger.info(`${JSON.stringify(request)}`, 'consumerHandler');
81
+ return true;
82
+ }
83
+ }
84
+
85
+ export default MessageConsumer;
@@ -0,0 +1,142 @@
1
+ import MessageModel from "../models/MessageModel";
2
+ import { generateCorrelationId } from "../Util/commonUtil";
3
+ import { Logger } from "../Util/logger";
4
+ import BaseRabbitMQClient from "./BaseRabbitMQClient";
5
+ import ConnectionManager from "./ConnectionManager";
6
+ import { PublishMessageInputType } from "./types/PublishMessageInputType";
7
+
8
+ class MessageProducer extends BaseRabbitMQClient{
9
+ private readonly correlationId:string;
10
+ public connectionManager:ConnectionManager;
11
+ constructor() {
12
+ super();
13
+ this.correlationId= generateCorrelationId();
14
+ this.connectionManager = new ConnectionManager();
15
+ }
16
+
17
+
18
+
19
+ /**
20
+ * Function to publish a message with retry
21
+ * @param queueName
22
+ * @param message
23
+ * @returns
24
+ */
25
+ public async publishMessage(request: PublishMessageInputType): Promise<boolean> {
26
+ const queueName: string = request.queueName;
27
+ const data: MessageModel = request.message;
28
+ console.log(data.message, queueName, 'message')
29
+ Logger.info('Reached:publishMessage', 'publishMessage');
30
+ const messageBuffer = Buffer.from(JSON.stringify(data?.message));
31
+ this.channel = this.connectionManager.getChannel();
32
+ try {
33
+ const isSent = await new Promise<boolean>((resolve, reject) => {
34
+ this.connection?.on('close', (err: any) => {
35
+ Logger.error(`RabbitMQ: bindConnectionEventHandler:close`, `Connection closed`, err);
36
+
37
+ });
38
+ let sent = this.channel?.sendToQueue('update_metadata_queue', Buffer.from(JSON.stringify('Hello world test')), {
39
+ persistent: true, // Ensures the message is persisted
40
+ // correlationId: data?.message?.correlationId,
41
+ });
42
+ console.log("publish message successfully")
43
+ // console.log(sent, 'send')
44
+ if (sent) {
45
+ Logger.debug(`Message sent successfully`, 'publishMessage', { data, queueName });
46
+ resolve(true);
47
+ } else {
48
+ Logger.error(`Failed to publish message.`, 'publishMessage', { message: messageBuffer.toString() });
49
+ reject(false);
50
+ }
51
+ });
52
+ console.log(isSent)
53
+ return true;;
54
+ } catch (error) {
55
+ console.log(error)
56
+ Logger.error(`Error sending message: ${error}`, 'sendMessage', error);
57
+ return false;
58
+ }
59
+ }
60
+
61
+ /**
62
+ * Function to publish a message with retry
63
+ * @param exchangeName
64
+ * @param routingKey
65
+ * @param message
66
+ * @param options
67
+ * @returns
68
+ */
69
+ public async publishMessageToExchange(
70
+ request: PublishMessageInputType
71
+ ): Promise<boolean> {
72
+ const exchangeName:string | undefined = request?.exchangeName ?? '';
73
+ const queueName:string = request.queueName;
74
+ const data:MessageModel = request?.message
75
+ // const options:object | null = request?.options; // Optional parameter for retry count if you wnats to override the default retry count
76
+ // const messageObj = {
77
+ // message,
78
+ // correlationId:this.correlationId,
79
+ // }
80
+ Logger.info('Reached:publishMessageToExchange', 'publishMessageToExchange');
81
+ // Publish the message
82
+ const messageBuffer = Buffer.from(JSON.stringify(data.message));
83
+ try {
84
+ const isSent = await new Promise<boolean>((resolve, reject) => {
85
+ // this.channel?.on
86
+ const sent = this.channel?.publish(exchangeName, queueName, messageBuffer,{
87
+ persistent: true, // Ensures the message is persisted
88
+ correlationId: this.correlationId,
89
+ });
90
+ if (sent) {
91
+ Logger.debug(`Message sent successfully`, 'publishMessageToExchange', { data, queueName });
92
+ resolve(true);
93
+ } else {
94
+ Logger.error(`Failed to publish message to exchange.`, 'publishMessageToExchange', { message: messageBuffer.toString() });
95
+ reject(false);
96
+ }
97
+ });
98
+ return isSent;
99
+ } catch (error) {
100
+ Logger.error(`Error sending message: ${error}`, 'sendMessage');
101
+ return false;
102
+ }
103
+ };
104
+
105
+ /**
106
+ * Funciton to message handler
107
+ */
108
+
109
+ public async messageHandler(request:PublishMessageInputType):Promise<boolean>{
110
+ Logger.info(`${JSON.stringify(request)}`, 'messageHandler');
111
+ return true;
112
+ }
113
+
114
+ /**
115
+ * Function to connect create to RabbitMQ
116
+ */
117
+ // public async createConnection(): Promise<ConnectionWrapper> {
118
+ // try {
119
+ // Logger.info('Reached to createConnection', 'createConnection');
120
+ // this.configManager.loadConfig(config?.RABBITMQ?.CONFIG_PATH);
121
+ // let url: string = `amqp://${this.configData?.username}:${this.configData?.password}@${this.configData?.host}`;
122
+ // // Create a connection to RabbitMQ server
123
+ // this.connection = await amqp.connect(url, { heartbeat: this.configData?.heartbeat });
124
+ // isConnectionOpen = true;
125
+ // // check the connection status
126
+ // this.bindConnectionEventHandler();
127
+ // // create channel
128
+ // this.channel = await this.connection.createConfirmChannel();
129
+ // Logger.info('RabbitMQ connected successfully! ', 'createConnection');
130
+ // // create exchange and queue and bind with exchange
131
+ // await this.setupQueuesAndExchanges();
132
+ // const connectionWrapper: ConnectionWrapper = { connection: this.connection, channel: this.channel }
133
+ // return connectionWrapper;
134
+ // } catch (error) {
135
+ // // Log and rethrow any errors that occur during connection
136
+ // Logger.error('Failed to connect to RabbitMQ', 'connection', (error as Error)?.message);
137
+ // return { connection: null, channel: null } as unknown as ConnectionWrapper;
138
+ // }
139
+ // }
140
+ }
141
+
142
+ export default MessageProducer;