@platform-x/hep-message-broker-client 1.1.15 → 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.
Files changed (50) 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.map +1 -0
  4. package/dist/src/Util/logger.js.map +1 -0
  5. package/dist/src/Util/requestTracer.js.map +1 -0
  6. package/dist/src/config/ConfigManager.js.map +1 -0
  7. package/dist/src/config/index.js.map +1 -0
  8. package/dist/src/index.js.map +1 -0
  9. package/dist/src/messageBroker/BaseRabbitMQClient.js.map +1 -0
  10. package/dist/src/messageBroker/ConnectionManager.js.map +1 -0
  11. package/dist/src/messageBroker/MessageBrokerClient.js.map +1 -0
  12. package/dist/src/messageBroker/MessageConsumer.js.map +1 -0
  13. package/dist/src/messageBroker/MessageProducer.js.map +1 -0
  14. package/dist/src/messageBroker/RabbitMQClient.js.map +1 -0
  15. package/dist/src/messageBroker/RetryManager.js.map +1 -0
  16. package/dist/src/messageBroker/interface/ConnectionWrapper.js.map +1 -0
  17. package/dist/src/messageBroker/interface/IMessageBrokerClient.js.map +1 -0
  18. package/dist/src/messageBroker/rabbitmq/MessageBroker.js +26 -24
  19. package/dist/src/messageBroker/rabbitmq/MessageBroker.js.map +1 -0
  20. package/dist/src/messageBroker/rabbitmq/MessageBrokerClient.js +33 -31
  21. package/dist/src/messageBroker/rabbitmq/MessageBrokerClient.js.map +1 -0
  22. package/dist/src/messageBroker/types/ActionType.js.map +1 -0
  23. package/dist/src/messageBroker/types/PublishMessageInputType.js.map +1 -0
  24. package/dist/src/models/MessageModel.js.map +1 -0
  25. package/dist/src/models/NotificationMessageModel.js.map +1 -0
  26. package/package.json +43 -43
  27. package/src/Util/commonUtil.ts +41 -0
  28. package/src/Util/constants.ts +9 -0
  29. package/src/Util/logger.ts +219 -0
  30. package/src/Util/requestTracer.ts +28 -0
  31. package/src/config/ConfigManager.ts +35 -0
  32. package/src/config/index.ts +38 -0
  33. package/src/index.ts +74 -0
  34. package/src/messageBroker/BaseRabbitMQClient.ts +30 -0
  35. package/src/messageBroker/ConnectionManager.ts +182 -0
  36. package/src/messageBroker/MessageBrokerClient.ts +88 -0
  37. package/src/messageBroker/MessageConsumer.ts +85 -0
  38. package/src/messageBroker/MessageProducer.ts +142 -0
  39. package/src/messageBroker/RabbitMQClient.ts +47 -0
  40. package/src/messageBroker/RetryManager.ts +64 -0
  41. package/src/messageBroker/interface/ConnectionWrapper.ts +7 -0
  42. package/src/messageBroker/interface/IMessageBrokerClient.ts +11 -0
  43. package/src/messageBroker/rabbitmq/MessageBroker.ts +525 -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/src/models/NotificationMessageModel.ts +0 -0
  49. package/tsconfig.json +73 -0
  50. 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,7 @@
1
+ import * as amqp from 'amqplib';
2
+
3
+ interface ConnectionWrapper {
4
+ connection: amqp.Connection,
5
+ channel: amqp.Channel
6
+ }
7
+ export default ConnectionWrapper;
@@ -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
+ }