@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.
- package/README.md +1 -1
- package/dist/src/Util/commonUtil.js.map +1 -0
- package/dist/src/Util/constants.js +8 -0
- package/dist/src/Util/constants.js.map +1 -0
- package/dist/src/Util/logger.js.map +1 -0
- package/dist/src/Util/requestTracer.js.map +1 -0
- package/dist/src/config/ConfigManager.js.map +1 -0
- package/dist/src/config/index.js +1 -1
- package/dist/src/config/index.js.map +1 -0
- package/dist/src/index.js +22 -1
- package/dist/src/index.js.map +1 -0
- package/dist/src/messageBroker/BaseRabbitMQClient.js.map +1 -0
- package/dist/src/messageBroker/ConnectionManager.js.map +1 -0
- package/dist/src/messageBroker/MessageBrokerClient.js.map +1 -0
- package/dist/src/messageBroker/MessageConsumer.js.map +1 -0
- package/dist/src/messageBroker/MessageProducer.js.map +1 -0
- package/dist/src/messageBroker/RabbitMQClient.js.map +1 -0
- package/dist/src/messageBroker/RetryManager.js.map +1 -0
- package/dist/src/messageBroker/interface/ConnectionWrapper.js.map +1 -0
- package/dist/src/messageBroker/interface/IMessageBrokerClient.js.map +1 -0
- package/dist/src/messageBroker/rabbitmq/MessageBrokerClient.js +5 -1
- package/dist/src/messageBroker/rabbitmq/MessageBrokerClient.js.map +1 -0
- package/dist/src/messageBroker/types/ActionType.js.map +1 -0
- package/dist/src/messageBroker/types/PublishMessageInputType.js.map +1 -0
- package/dist/src/models/MessageModel.js.map +1 -0
- package/dist/src/models/NotificationMessageModel.js.map +1 -0
- package/package.json +43 -40
- package/src/Util/commonUtil.ts +41 -0
- package/src/Util/constants.ts +4 -0
- package/src/Util/logger.ts +219 -0
- package/src/Util/requestTracer.ts +28 -0
- package/src/config/ConfigManager.ts +35 -0
- package/src/config/index.ts +31 -0
- package/src/index.ts +73 -0
- package/src/messageBroker/BaseRabbitMQClient.ts +30 -0
- package/src/messageBroker/ConnectionManager.ts +182 -0
- package/src/messageBroker/MessageBrokerClient.ts +88 -0
- package/src/messageBroker/MessageConsumer.ts +85 -0
- package/src/messageBroker/MessageProducer.ts +142 -0
- package/src/messageBroker/RabbitMQClient.ts +47 -0
- package/src/messageBroker/RetryManager.ts +64 -0
- package/src/messageBroker/interface/ConnectionWrapper.ts +7 -0
- package/src/messageBroker/interface/IMessageBrokerClient.ts +11 -0
- package/src/messageBroker/rabbitmq/MessageBrokerClient.ts +681 -0
- package/src/messageBroker/types/ActionType.ts +1 -0
- package/src/messageBroker/types/PublishMessageInputType.ts +8 -0
- package/src/models/MessageModel.ts +14 -0
- package/tsconfig.json +73 -0
- package/dist/src/Util/commonUtil.d.ts +0 -16
- package/dist/src/Util/logger.d.ts +0 -68
- package/dist/src/Util/requestTracer.d.ts +0 -7
- package/dist/src/config/ConfigManager.d.ts +0 -9
- package/dist/src/config/index.d.ts +0 -29
- package/dist/src/index.d.ts +0 -2
- package/dist/src/messageBroker/BaseRabbitMQClient.d.ts +0 -16
- package/dist/src/messageBroker/ConnectionManager.d.ts +0 -60
- package/dist/src/messageBroker/MessageBrokerClient.d.ts +0 -34
- package/dist/src/messageBroker/MessageConsumer.d.ts +0 -26
- package/dist/src/messageBroker/MessageProducer.d.ts +0 -29
- package/dist/src/messageBroker/RabbitMQClient.d.ts +0 -12
- package/dist/src/messageBroker/RetryManager.d.ts +0 -23
- package/dist/src/messageBroker/interface/ConnectionWrapper.d.ts +0 -6
- package/dist/src/messageBroker/interface/IMessageBrokerClient.d.ts +0 -7
- package/dist/src/messageBroker/rabbitmq/MessageBrokerClient.d.ts +0 -122
- package/dist/src/messageBroker/types/ActionType.d.ts +0 -1
- package/dist/src/messageBroker/types/PublishMessageInputType.d.ts +0 -7
- package/dist/src/models/MessageModel.d.ts +0 -5
- /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;
|