@platform-x/hep-message-broker-client 1.1.14 → 1.1.16
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.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.map +1 -0
- 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/MessageBroker.js +31 -29
- package/dist/src/messageBroker/rabbitmq/MessageBroker.js.map +1 -0
- package/dist/src/messageBroker/rabbitmq/MessageBrokerClient.js +33 -31
- 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 -43
- package/src/Util/commonUtil.ts +41 -0
- package/src/Util/constants.ts +9 -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 +38 -0
- package/src/index.ts +74 -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/MessageBroker.ts +525 -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/src/models/NotificationMessageModel.ts +0 -0
- package/tsconfig.json +73 -0
- package/rabbitMQConfig.json +0 -344
|
@@ -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;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
// Import the amqplib library for RabbitMQ
|
|
2
|
+
import { Logger } from '../Util/logger';
|
|
3
|
+
import BaseRabbitMQClient from './BaseRabbitMQClient';
|
|
4
|
+
import ConnectionManager from './ConnectionManager';
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
export class RabbitMQClient extends BaseRabbitMQClient {
|
|
8
|
+
constructor() {
|
|
9
|
+
super();
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Function to initialize the RabbitMQ connection
|
|
14
|
+
*/
|
|
15
|
+
public async initialize() {
|
|
16
|
+
try {
|
|
17
|
+
Logger.info('Reached to initialize', 'initialize');
|
|
18
|
+
// Create a connection to RabbitMQ server
|
|
19
|
+
const connectionManager = await ConnectionManager.getInstance();
|
|
20
|
+
await connectionManager.createConnection();
|
|
21
|
+
Logger.info('RabbitMQ connection created', 'initialize');
|
|
22
|
+
} catch (error) {
|
|
23
|
+
// Log and rethrow any errors that occur during initialization
|
|
24
|
+
Logger.error('Failed to create RabbitMQ connection', 'initialize', error);
|
|
25
|
+
throw error;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Function to close the connection and channel
|
|
31
|
+
*/
|
|
32
|
+
public async disconnect() {
|
|
33
|
+
try {
|
|
34
|
+
Logger.info('Reached to disconnect', 'disconnect');
|
|
35
|
+
// Close the channel
|
|
36
|
+
await this.channel?.close();
|
|
37
|
+
// Close the connection
|
|
38
|
+
await this.connection?.close();
|
|
39
|
+
Logger.info('RabbitMQ connection closed', 'disconnect');
|
|
40
|
+
} catch (error) {
|
|
41
|
+
// Log and rethrow any errors that occur during closing
|
|
42
|
+
Logger.error('Failed to close RabbitMQ connection', 'disconnect', error);
|
|
43
|
+
throw error;
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { Logger } from '../Util/logger';
|
|
2
|
+
type ActionType<T> = (input: T) => void;
|
|
3
|
+
|
|
4
|
+
class RetryManager<T>{
|
|
5
|
+
private static instance: RetryManager<any>;
|
|
6
|
+
private readonly max_retry:number;
|
|
7
|
+
private readonly retry_delay:string[]|string;
|
|
8
|
+
|
|
9
|
+
constructor(max_retry:number, retry_delay:string){
|
|
10
|
+
this.max_retry = max_retry;
|
|
11
|
+
this.retry_delay = retry_delay?.split("|");
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Function for create singlton class instance and return instance
|
|
16
|
+
* @param max_retry
|
|
17
|
+
* @param retry_delay
|
|
18
|
+
* @returns
|
|
19
|
+
*/
|
|
20
|
+
public static getInstance<T>(max_retry: number, retry_delay: string): RetryManager<T> {
|
|
21
|
+
if (!RetryManager.instance) {
|
|
22
|
+
RetryManager.instance = new RetryManager<T>(max_retry, retry_delay);
|
|
23
|
+
}
|
|
24
|
+
return RetryManager.instance as RetryManager<T>;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Function for perform action with retry
|
|
28
|
+
* @param actionHandler
|
|
29
|
+
* @param context
|
|
30
|
+
* @param failActionHandler
|
|
31
|
+
* @returns
|
|
32
|
+
*/
|
|
33
|
+
public async performActionWithRetry(actionHandler:ActionType<T>, context:T, failActionHandler:ActionType<T>):Promise<boolean>{
|
|
34
|
+
Logger.info("Reached: in perform action with retry", "performActionWithRetry")
|
|
35
|
+
let attempt: number = 0;
|
|
36
|
+
while (attempt < this.max_retry) {
|
|
37
|
+
try {
|
|
38
|
+
actionHandler(context);
|
|
39
|
+
return true;
|
|
40
|
+
} catch (error) {
|
|
41
|
+
attempt++;
|
|
42
|
+
Logger.error(`Failed to publish message. Attempt ${attempt} of ${this.max_retry}. Error:`, 'performActionWithRetry', { message: (error as Error).message });
|
|
43
|
+
if (attempt >= this.max_retry) {
|
|
44
|
+
Logger.error('Max retries reached. Failed to publish message.', 'performActionWithRetry');
|
|
45
|
+
// Optionally: Log or persist the failed message to a DB, file, or other storage for manual intervention
|
|
46
|
+
failActionHandler(context);
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
// Wait before retrying (Exponential Backoff)
|
|
50
|
+
let retryDelay: number;
|
|
51
|
+
if(this.retry_delay.length-1 === attempt){
|
|
52
|
+
retryDelay = Number(this.retry_delay[attempt - 1]);
|
|
53
|
+
}else{
|
|
54
|
+
retryDelay = Number(this.retry_delay[this.retry_delay.length-1]);
|
|
55
|
+
}
|
|
56
|
+
Logger.info(`Retrying in ${retryDelay / 1000} seconds...`, 'performActionWithRetry');
|
|
57
|
+
await new Promise((resolve) => setTimeout(resolve, retryDelay));
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
}
|
|
64
|
+
export default RetryManager;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { PublishMessageInputType } from "../types/PublishMessageInputType";
|
|
2
|
+
|
|
3
|
+
export interface IMessageBrokerClient {
|
|
4
|
+
initialize(configData: object | null): void;
|
|
5
|
+
disconnect(): void;
|
|
6
|
+
// will create a class for publishOptions instead of object
|
|
7
|
+
publishMessage(request:PublishMessageInputType): Promise<boolean>;
|
|
8
|
+
// will create a class for publishOptions instead of object
|
|
9
|
+
publishMessageToExchange(request: PublishMessageInputType):Promise<boolean>;
|
|
10
|
+
// publish confirm in publishMessage need to implement
|
|
11
|
+
}
|