rabbitmq-sdk 0.0.1-security → 1.2.0

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.

Potentially problematic release.


This version of rabbitmq-sdk might be problematic. Click here for more details.

Files changed (140) hide show
  1. package/.eslintrc.js +23 -0
  2. package/.kiro/specs/sdk-rabbitmq/design.md +369 -0
  3. package/.kiro/specs/sdk-rabbitmq/requirements.md +97 -0
  4. package/.kiro/specs/sdk-rabbitmq/tasks.md +248 -0
  5. package/README.md +273 -5
  6. package/bun.lock +790 -0
  7. package/config.example.json +13 -0
  8. package/dist/components/ConfigurationManager.d.ts +35 -0
  9. package/dist/components/ConfigurationManager.d.ts.map +1 -0
  10. package/dist/components/ConfigurationManager.js +118 -0
  11. package/dist/components/ConfigurationManager.js.map +1 -0
  12. package/dist/components/ConnectionManager.d.ts +93 -0
  13. package/dist/components/ConnectionManager.d.ts.map +1 -0
  14. package/dist/components/ConnectionManager.js +349 -0
  15. package/dist/components/ConnectionManager.js.map +1 -0
  16. package/dist/components/DLQHandler.d.ts +81 -0
  17. package/dist/components/DLQHandler.d.ts.map +1 -0
  18. package/dist/components/DLQHandler.js +228 -0
  19. package/dist/components/DLQHandler.js.map +1 -0
  20. package/dist/components/Logger.d.ts +77 -0
  21. package/dist/components/Logger.d.ts.map +1 -0
  22. package/dist/components/Logger.js +193 -0
  23. package/dist/components/Logger.js.map +1 -0
  24. package/dist/components/MessagePublisher.d.ts +49 -0
  25. package/dist/components/MessagePublisher.d.ts.map +1 -0
  26. package/dist/components/MessagePublisher.js +158 -0
  27. package/dist/components/MessagePublisher.js.map +1 -0
  28. package/dist/components/MessageSubscriber.d.ts +108 -0
  29. package/dist/components/MessageSubscriber.d.ts.map +1 -0
  30. package/dist/components/MessageSubscriber.js +503 -0
  31. package/dist/components/MessageSubscriber.js.map +1 -0
  32. package/dist/components/ResourceCreator.d.ts +89 -0
  33. package/dist/components/ResourceCreator.d.ts.map +1 -0
  34. package/dist/components/ResourceCreator.js +352 -0
  35. package/dist/components/ResourceCreator.js.map +1 -0
  36. package/dist/components/SdkRabbitmq.d.ts +103 -0
  37. package/dist/components/SdkRabbitmq.d.ts.map +1 -0
  38. package/dist/components/SdkRabbitmq.js +364 -0
  39. package/dist/components/SdkRabbitmq.js.map +1 -0
  40. package/dist/components/index.d.ts +9 -0
  41. package/dist/components/index.d.ts.map +1 -0
  42. package/dist/components/index.js +20 -0
  43. package/dist/components/index.js.map +1 -0
  44. package/dist/index.d.ts +5 -0
  45. package/dist/index.d.ts.map +1 -0
  46. package/dist/index.js +27 -0
  47. package/dist/index.js.map +1 -0
  48. package/dist/interfaces/IConfiguration.d.ts +35 -0
  49. package/dist/interfaces/IConfiguration.d.ts.map +1 -0
  50. package/dist/interfaces/IConfiguration.js +3 -0
  51. package/dist/interfaces/IConfiguration.js.map +1 -0
  52. package/dist/interfaces/IConnection.d.ts +21 -0
  53. package/dist/interfaces/IConnection.d.ts.map +1 -0
  54. package/dist/interfaces/IConnection.js +3 -0
  55. package/dist/interfaces/IConnection.js.map +1 -0
  56. package/dist/interfaces/IDLQ.d.ts +12 -0
  57. package/dist/interfaces/IDLQ.d.ts.map +1 -0
  58. package/dist/interfaces/IDLQ.js +3 -0
  59. package/dist/interfaces/IDLQ.js.map +1 -0
  60. package/dist/interfaces/IErrors.d.ts +33 -0
  61. package/dist/interfaces/IErrors.d.ts.map +1 -0
  62. package/dist/interfaces/IErrors.js +56 -0
  63. package/dist/interfaces/IErrors.js.map +1 -0
  64. package/dist/interfaces/ILogger.d.ts +14 -0
  65. package/dist/interfaces/ILogger.d.ts.map +1 -0
  66. package/dist/interfaces/ILogger.js +3 -0
  67. package/dist/interfaces/ILogger.js.map +1 -0
  68. package/dist/interfaces/IMessage.d.ts +52 -0
  69. package/dist/interfaces/IMessage.d.ts.map +1 -0
  70. package/dist/interfaces/IMessage.js +3 -0
  71. package/dist/interfaces/IMessage.js.map +1 -0
  72. package/dist/interfaces/IResource.d.ts +31 -0
  73. package/dist/interfaces/IResource.d.ts.map +1 -0
  74. package/dist/interfaces/IResource.js +3 -0
  75. package/dist/interfaces/IResource.js.map +1 -0
  76. package/dist/interfaces/ISdkRabbitmq.d.ts +17 -0
  77. package/dist/interfaces/ISdkRabbitmq.d.ts.map +1 -0
  78. package/dist/interfaces/ISdkRabbitmq.js +3 -0
  79. package/dist/interfaces/ISdkRabbitmq.js.map +1 -0
  80. package/dist/interfaces/index.d.ts +9 -0
  81. package/dist/interfaces/index.d.ts.map +1 -0
  82. package/dist/interfaces/index.js +33 -0
  83. package/dist/interfaces/index.js.map +1 -0
  84. package/dist/utils/configSchema.d.ts +8 -0
  85. package/dist/utils/configSchema.d.ts.map +1 -0
  86. package/dist/utils/configSchema.js +51 -0
  87. package/dist/utils/configSchema.js.map +1 -0
  88. package/docker-compose.yml +24 -0
  89. package/example.ts +65 -0
  90. package/examples/README-dynamic-routing.md +155 -0
  91. package/examples/bind-unbind-example.js +56 -0
  92. package/examples/test-chatbot-exchange.ts +83 -0
  93. package/examples/test-dynamic-routing-flow.js +299 -0
  94. package/examples/test-dynamic-routing-flow.ts +355 -0
  95. package/examples/test-no-disconnect.ts +0 -0
  96. package/examples/test-raw-rabbitmq.js +68 -0
  97. package/examples/test-same-channel.ts +81 -0
  98. package/examples/test-schedule-flow.ts +713 -0
  99. package/examples/test-simple-greeting.ts +66 -0
  100. package/examples/test-simple-schedule.ts +76 -0
  101. package/examples/test-wildcard.ts +364 -0
  102. package/jest.config.js +17 -0
  103. package/package.json +42 -4
  104. package/preinstall.js +1 -0
  105. package/prompts/test-dynamic-routing-flow.md +46 -0
  106. package/run.js +4 -0
  107. package/scripts/run-dynamic-routing-test.ts +31 -0
  108. package/src/.gitkeep +1 -0
  109. package/src/components/.gitkeep +1 -0
  110. package/src/components/ConfigurationManager.ts +104 -0
  111. package/src/components/ConnectionManager.ts +357 -0
  112. package/src/components/DLQHandler.ts +271 -0
  113. package/src/components/Logger.ts +224 -0
  114. package/src/components/MessagePublisher.ts +180 -0
  115. package/src/components/MessageSubscriber.ts +597 -0
  116. package/src/components/ResourceCreator.ts +411 -0
  117. package/src/components/SdkRabbitmq.ts +443 -0
  118. package/src/components/__tests__/ConfigurationManager.test.ts +357 -0
  119. package/src/components/__tests__/ConnectionManager.test.ts +387 -0
  120. package/src/components/__tests__/DLQHandler.test.ts +399 -0
  121. package/src/components/__tests__/Logger.test.ts +354 -0
  122. package/src/components/__tests__/MessagePublisher.test.ts +337 -0
  123. package/src/components/__tests__/MessageSubscriber.test.ts +542 -0
  124. package/src/components/__tests__/ResourceCreator.test.ts +465 -0
  125. package/src/components/__tests__/SdkRabbitmq.integration.test.ts +433 -0
  126. package/src/components/index.ts +8 -0
  127. package/src/index.ts +11 -0
  128. package/src/interfaces/.gitkeep +1 -0
  129. package/src/interfaces/IConfiguration.ts +38 -0
  130. package/src/interfaces/IConnection.ts +27 -0
  131. package/src/interfaces/IDLQ.ts +13 -0
  132. package/src/interfaces/IErrors.ts +53 -0
  133. package/src/interfaces/ILogger.ts +16 -0
  134. package/src/interfaces/IMessage.ts +65 -0
  135. package/src/interfaces/IResource.ts +35 -0
  136. package/src/interfaces/ISdkRabbitmq.ts +26 -0
  137. package/src/interfaces/index.ts +23 -0
  138. package/src/utils/.gitkeep +1 -0
  139. package/src/utils/configSchema.ts +58 -0
  140. package/tsconfig.json +34 -0
@@ -0,0 +1,31 @@
1
+ #!/usr/bin/env ts-node
2
+
3
+ /**
4
+ * Script para executar o teste de fluxo de roteamento dinâmico
5
+ *
6
+ * Uso:
7
+ * npm run build && npx ts-node scripts/run-dynamic-routing-test.ts
8
+ *
9
+ * Ou compile primeiro:
10
+ * npm run build && node dist/examples/test-dynamic-routing-flow.js
11
+ */
12
+
13
+ import { testDynamicRoutingFlow } from '../examples/test-dynamic-routing-flow';
14
+
15
+ async function main(): Promise<void> {
16
+ console.log('🚀 Executando teste de fluxo de roteamento dinâmico...\n');
17
+
18
+ try {
19
+ await testDynamicRoutingFlow();
20
+ console.log('\n✅ Teste executado com sucesso!');
21
+ process.exit(0);
22
+ } catch (error) {
23
+ console.error('\n❌ Erro durante a execução do teste:', error);
24
+ process.exit(1);
25
+ }
26
+ }
27
+
28
+ // Executar apenas se este arquivo for chamado diretamente
29
+ if (require.main === module) {
30
+ main();
31
+ }
package/src/.gitkeep ADDED
@@ -0,0 +1 @@
1
+ # This file ensures the src directory is tracked by git
@@ -0,0 +1 @@
1
+ # This file ensures the components directory is tracked by git
@@ -0,0 +1,104 @@
1
+ import * as fs from 'fs';
2
+ import * as path from 'path';
3
+ import { IConfiguration, IConfigurationManager } from '../interfaces/IConfiguration';
4
+ import { ConfigurationError } from '../interfaces/IErrors';
5
+ import { validateConfigurationSchema } from '../utils/configSchema';
6
+
7
+ /**
8
+ * Configuration manager that handles loading and validating configuration from config.json
9
+ */
10
+ export class ConfigurationManager implements IConfigurationManager {
11
+ private static instance: ConfigurationManager;
12
+ private cachedConfig: IConfiguration | null = null;
13
+ private readonly configPath: string;
14
+
15
+ private constructor() {
16
+ // Config file should be at project root
17
+ this.configPath = path.join(process.cwd(), 'config.json');
18
+ }
19
+
20
+ /**
21
+ * Get singleton instance of ConfigurationManager
22
+ */
23
+ public static getInstance(): ConfigurationManager {
24
+ if (!ConfigurationManager.instance) {
25
+ ConfigurationManager.instance = new ConfigurationManager();
26
+ }
27
+ return ConfigurationManager.instance;
28
+ }
29
+
30
+ /**
31
+ * Load configuration from config.json file
32
+ * @returns Validated configuration object
33
+ * @throws ConfigurationError if file doesn't exist or is invalid
34
+ */
35
+ public loadConfig(): IConfiguration {
36
+ // Return cached config if available
37
+ if (this.cachedConfig) {
38
+ return this.cachedConfig;
39
+ }
40
+
41
+ try {
42
+ // Check if config file exists
43
+ if (!fs.existsSync(this.configPath)) {
44
+ throw new ConfigurationError(
45
+ `Configuration file not found at ${this.configPath}. Please create a config.json file in your project root.`,
46
+ { configPath: this.configPath }
47
+ );
48
+ }
49
+
50
+ // Read and parse config file
51
+ const configContent = fs.readFileSync(this.configPath, 'utf-8');
52
+ let parsedConfig: any;
53
+
54
+ try {
55
+ parsedConfig = JSON.parse(configContent);
56
+ } catch (parseError) {
57
+ throw new ConfigurationError(
58
+ `Invalid JSON in configuration file: ${parseError instanceof Error ? parseError.message : 'Unknown parsing error'}`,
59
+ { configPath: this.configPath, parseError }
60
+ );
61
+ }
62
+
63
+ // Validate configuration schema
64
+ this.validateConfig(parsedConfig);
65
+
66
+ // Cache the validated configuration
67
+ this.cachedConfig = parsedConfig as IConfiguration;
68
+
69
+ return this.cachedConfig;
70
+ } catch (error) {
71
+ if (error instanceof ConfigurationError) {
72
+ throw error;
73
+ }
74
+
75
+ throw new ConfigurationError(
76
+ `Failed to load configuration: ${error instanceof Error ? error.message : 'Unknown error'}`,
77
+ { configPath: this.configPath, originalError: error }
78
+ );
79
+ }
80
+ }
81
+
82
+ /**
83
+ * Validate configuration schema
84
+ * @param config - Configuration object to validate
85
+ * @throws ConfigurationError if validation fails
86
+ */
87
+ public validateConfig(config: any): void {
88
+ validateConfigurationSchema(config);
89
+ }
90
+
91
+ /**
92
+ * Clear cached configuration (useful for testing)
93
+ */
94
+ public clearCache(): void {
95
+ this.cachedConfig = null;
96
+ }
97
+
98
+ /**
99
+ * Get the configuration file path
100
+ */
101
+ public getConfigPath(): string {
102
+ return this.configPath;
103
+ }
104
+ }
@@ -0,0 +1,357 @@
1
+ import * as amqp from 'amqplib';
2
+ import { IConnectionManager } from '../interfaces/IConnection';
3
+ import { IConfiguration } from '../interfaces/IConfiguration';
4
+ import { Logger } from './Logger';
5
+
6
+ /**
7
+ * Connection states for tracking connection status
8
+ */
9
+ export enum ConnectionState {
10
+ DISCONNECTED = 'disconnected',
11
+ CONNECTING = 'connecting',
12
+ CONNECTED = 'connected',
13
+ RECONNECTING = 'reconnecting',
14
+ FAILED = 'failed'
15
+ }
16
+
17
+ /**
18
+ * ConnectionManager implements singleton pattern for RabbitMQ connections
19
+ * Manages connection state and provides auto-reconnection capabilities
20
+ */
21
+ export class ConnectionManager implements IConnectionManager {
22
+ private static instance: ConnectionManager | null = null;
23
+ private connection: amqp.Connection | null = null;
24
+ private connectionState: ConnectionState = ConnectionState.DISCONNECTED;
25
+ private config: IConfiguration;
26
+ private connectionLostCallbacks: (() => void)[] = [];
27
+ private operationQueue: (() => Promise<void>)[] = [];
28
+ private reconnectAttempts = 0;
29
+ private maxReconnectAttempts = 10;
30
+ private baseRetryDelay = 1000; // 1 second
31
+ private maxRetryDelay = 30000; // 30 seconds
32
+ private reconnectTimer: ReturnType<typeof setTimeout> | null = null;
33
+ private logger: Logger;
34
+
35
+ /**
36
+ * Private constructor to enforce singleton pattern
37
+ */
38
+ private constructor(config: IConfiguration) {
39
+ this.config = config;
40
+ this.logger = Logger.createComponentLogger('ConnectionManager', config.logging);
41
+ }
42
+
43
+ /**
44
+ * Get singleton instance of ConnectionManager
45
+ */
46
+ public static getInstance(config: IConfiguration): ConnectionManager {
47
+ if (!ConnectionManager.instance) {
48
+ ConnectionManager.instance = new ConnectionManager(config);
49
+ }
50
+ return ConnectionManager.instance;
51
+ }
52
+
53
+ /**
54
+ * Establish connection to RabbitMQ
55
+ */
56
+ public async connect(): Promise<amqp.Connection> {
57
+ if (this.connection && this.connectionState === ConnectionState.CONNECTED) {
58
+ return this.connection;
59
+ }
60
+
61
+ if (this.connectionState === ConnectionState.CONNECTING ||
62
+ this.connectionState === ConnectionState.RECONNECTING) {
63
+ // Wait for existing connection attempt
64
+ return new Promise<amqp.Connection>((resolve, reject) => {
65
+ const checkConnection = (): void => {
66
+ if (this.connection && this.connectionState === ConnectionState.CONNECTED) {
67
+ resolve(this.connection);
68
+ } else if (this.connectionState === ConnectionState.FAILED) {
69
+ reject(new Error('Connection failed'));
70
+ } else {
71
+ setTimeout(checkConnection, 100);
72
+ }
73
+ };
74
+ checkConnection();
75
+ });
76
+ }
77
+
78
+ this.connectionState = ConnectionState.CONNECTING;
79
+
80
+ try {
81
+ this.connection = await amqp.connect(this.config.url) as unknown as amqp.Connection;
82
+ this.connectionState = ConnectionState.CONNECTED;
83
+ this.reconnectAttempts = 0;
84
+
85
+ this.logger.logConnectionState(ConnectionState.CONNECTED, { url: this.config.url });
86
+
87
+ // Set up connection event handlers
88
+ this.setupConnectionEventHandlers();
89
+
90
+ // Process queued operations
91
+ await this.processQueuedOperations();
92
+
93
+ return this.connection;
94
+ } catch (error) {
95
+ this.connectionState = ConnectionState.FAILED;
96
+ this.logger.logError('Failed to connect to RabbitMQ', error as Error, { url: this.config.url });
97
+ throw new Error(`Failed to connect to RabbitMQ: ${error instanceof Error ? error.message : 'Unknown error'}`);
98
+ }
99
+ }
100
+
101
+ /**
102
+ * Get current connection instance
103
+ */
104
+ public getConnection(): amqp.Connection | null {
105
+ return this.connection;
106
+ }
107
+
108
+ /**
109
+ * Check if currently connected
110
+ */
111
+ public isConnected(): boolean {
112
+ return this.connectionState === ConnectionState.CONNECTED && this.connection !== null;
113
+ }
114
+
115
+ /**
116
+ * Disconnect from RabbitMQ
117
+ */
118
+ public async disconnect(): Promise<void> {
119
+ if (this.reconnectTimer) {
120
+ clearTimeout(this.reconnectTimer);
121
+ this.reconnectTimer = null;
122
+ }
123
+
124
+ if (this.connection) {
125
+ try {
126
+ await (this.connection as any).close();
127
+ } catch (error) {
128
+ // Ignore errors during disconnect
129
+ }
130
+ this.connection = null;
131
+ }
132
+
133
+ this.connectionState = ConnectionState.DISCONNECTED;
134
+ this.reconnectAttempts = 0;
135
+ this.operationQueue = [];
136
+
137
+ this.logger.logConnectionState(ConnectionState.DISCONNECTED);
138
+ }
139
+
140
+ /**
141
+ * Register callback for connection lost events
142
+ */
143
+ public onConnectionLost(callback: () => void): void {
144
+ this.connectionLostCallbacks.push(callback);
145
+ }
146
+
147
+ /**
148
+ * Get current connection state
149
+ */
150
+ public getConnectionState(): ConnectionState {
151
+ return this.connectionState;
152
+ }
153
+
154
+ /**
155
+ * Queue operation to be executed after reconnection
156
+ */
157
+ public queueOperation(operation: () => Promise<void>): void {
158
+ if (this.connectionState === ConnectionState.RECONNECTING ||
159
+ this.connectionState === ConnectionState.CONNECTING) {
160
+ this.operationQueue.push(operation);
161
+ } else if (this.connectionState === ConnectionState.CONNECTED) {
162
+ // Execute immediately if connected
163
+ operation().catch(error => {
164
+ this.logger.logError('Error executing queued operation', error as Error);
165
+ });
166
+ } else {
167
+ // Queue for later if disconnected
168
+ this.operationQueue.push(operation);
169
+ }
170
+ }
171
+
172
+ /**
173
+ * Execute operation with automatic queuing during reconnection
174
+ */
175
+ public async executeOperation<T>(operation: () => Promise<T>): Promise<T> {
176
+ if (this.connectionState === ConnectionState.CONNECTED && this.connection) {
177
+ return await operation();
178
+ }
179
+
180
+ // Queue operation and wait for reconnection
181
+ return new Promise<T>((resolve, reject) => {
182
+ const wrappedOperation = async (): Promise<void> => {
183
+ try {
184
+ const result = await operation();
185
+ resolve(result);
186
+ } catch (error) {
187
+ reject(error);
188
+ }
189
+ };
190
+ this.queueOperation(wrappedOperation);
191
+ });
192
+ }
193
+
194
+ /**
195
+ * Set up event handlers for connection
196
+ */
197
+ private setupConnectionEventHandlers(): void {
198
+ if (!this.connection) return;
199
+
200
+ this.connection.on('error', (error: Error) => {
201
+ this.logger.logError('RabbitMQ connection error', error);
202
+ this.handleConnectionLoss();
203
+ });
204
+
205
+ this.connection.on('close', () => {
206
+ this.logger.warn('RabbitMQ connection closed');
207
+ this.handleConnectionLoss();
208
+ });
209
+
210
+ this.connection.on('blocked', (reason: string) => {
211
+ this.logger.warn('RabbitMQ connection blocked', { reason });
212
+ });
213
+
214
+ this.connection.on('unblocked', () => {
215
+ this.logger.info('RabbitMQ connection unblocked');
216
+ });
217
+ }
218
+
219
+ /**
220
+ * Handle connection loss and initiate reconnection
221
+ */
222
+ private handleConnectionLoss(): void {
223
+ if (this.connectionState === ConnectionState.RECONNECTING ||
224
+ this.connectionState === ConnectionState.DISCONNECTED) {
225
+ return; // Already handling reconnection or intentionally disconnected
226
+ }
227
+
228
+ this.connection = null;
229
+ this.connectionState = ConnectionState.RECONNECTING;
230
+
231
+ this.logger.logConnectionState(ConnectionState.RECONNECTING, {
232
+ queuedOperations: this.operationQueue.length
233
+ });
234
+
235
+ // Notify callbacks about connection loss
236
+ this.connectionLostCallbacks.forEach(callback => {
237
+ try {
238
+ callback();
239
+ } catch (error) {
240
+ this.logger.logError('Error in connection lost callback', error as Error);
241
+ }
242
+ });
243
+
244
+ // Start reconnection process
245
+ this.startReconnection();
246
+ }
247
+
248
+ /**
249
+ * Start reconnection process with exponential backoff
250
+ * Implements exponential backoff: 1s, 2s, 4s, 8s, 16s, 30s (max)
251
+ */
252
+ private startReconnection(): void {
253
+ if (this.reconnectAttempts >= this.maxReconnectAttempts) {
254
+ this.logger.error('Max reconnection attempts reached. Connection failed permanently.', {
255
+ maxAttempts: this.maxReconnectAttempts,
256
+ queuedOperations: this.operationQueue.length
257
+ });
258
+ this.connectionState = ConnectionState.FAILED;
259
+ this.logger.logConnectionState(ConnectionState.FAILED);
260
+
261
+ // Reject all queued operations
262
+ this.operationQueue.forEach(operation => {
263
+ operation().catch(() => {
264
+ // Operations will fail, but we need to clear the queue
265
+ });
266
+ });
267
+ this.operationQueue = [];
268
+ return;
269
+ }
270
+
271
+ // Calculate exponential backoff delay: 1s, 2s, 4s, 8s, 16s, max 30s
272
+ const delay = Math.min(
273
+ this.baseRetryDelay * Math.pow(2, this.reconnectAttempts),
274
+ this.maxRetryDelay
275
+ );
276
+
277
+ this.logger.info('Connection lost. Starting reconnection process', {
278
+ queuedOperations: this.operationQueue.length,
279
+ delayMs: delay,
280
+ attempt: this.reconnectAttempts + 1,
281
+ maxAttempts: this.maxReconnectAttempts
282
+ });
283
+
284
+ this.reconnectTimer = setTimeout(async () => {
285
+ this.reconnectAttempts++;
286
+
287
+ try {
288
+ this.logger.logOperation('reconnect', `Attempting reconnection ${this.reconnectAttempts}/${this.maxReconnectAttempts}`);
289
+
290
+ // Set state to connecting before attempting connection
291
+ this.connectionState = ConnectionState.CONNECTING;
292
+ this.connection = await amqp.connect(this.config.url) as unknown as amqp.Connection;
293
+ this.connectionState = ConnectionState.CONNECTED;
294
+
295
+ this.logger.logConnectionState(ConnectionState.CONNECTED, { url: this.config.url });
296
+
297
+ // Set up connection event handlers
298
+ this.setupConnectionEventHandlers();
299
+
300
+ // Process queued operations
301
+ await this.processQueuedOperations();
302
+
303
+ this.logger.info('Successfully reconnected to RabbitMQ', {
304
+ queuedOperations: this.operationQueue.length,
305
+ attempt: this.reconnectAttempts
306
+ });
307
+ } catch (error) {
308
+ this.connectionState = ConnectionState.RECONNECTING;
309
+ this.logger.logError(`Reconnection attempt ${this.reconnectAttempts} failed`, error as Error, {
310
+ attempt: this.reconnectAttempts,
311
+ maxAttempts: this.maxReconnectAttempts
312
+ });
313
+ this.startReconnection(); // Try again with increased delay
314
+ }
315
+ }, delay);
316
+ }
317
+
318
+ /**
319
+ * Process operations that were queued during reconnection
320
+ */
321
+ private async processQueuedOperations(): Promise<void> {
322
+ if (this.operationQueue.length === 0) {
323
+ return;
324
+ }
325
+
326
+ this.logger.logOperation('processQueue', `Processing ${this.operationQueue.length} queued operations after reconnection`);
327
+
328
+ const operations = [...this.operationQueue];
329
+ this.operationQueue = [];
330
+
331
+ let successCount = 0;
332
+ let errorCount = 0;
333
+
334
+ for (const operation of operations) {
335
+ try {
336
+ await operation();
337
+ successCount++;
338
+ } catch (error) {
339
+ errorCount++;
340
+ this.logger.logError('Error processing queued operation', error as Error);
341
+ }
342
+ }
343
+
344
+ this.logger.info('Processed queued operations', {
345
+ successful: successCount,
346
+ failed: errorCount,
347
+ total: operations.length
348
+ });
349
+ }
350
+
351
+ /**
352
+ * Reset singleton instance (for testing purposes)
353
+ */
354
+ public static resetInstance(): void {
355
+ ConnectionManager.instance = null;
356
+ }
357
+ }