@onlineapps/conn-infra-mq 1.1.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.
- package/LICENSE +21 -0
- package/README.md +223 -0
- package/package.json +96 -0
- package/src/BaseClient.js +219 -0
- package/src/ConnectorMQClient.js +446 -0
- package/src/config/configSchema.js +70 -0
- package/src/config/defaultConfig.js +48 -0
- package/src/index.js +65 -0
- package/src/layers/ForkJoinHandler.js +312 -0
- package/src/layers/QueueManager.js +263 -0
- package/src/layers/RPCHandler.js +324 -0
- package/src/layers/RetryHandler.js +370 -0
- package/src/layers/WorkflowRouter.js +136 -0
- package/src/transports/rabbitmqClient.js +216 -0
- package/src/transports/transportFactory.js +33 -0
- package/src/utils/errorHandler.js +120 -0
- package/src/utils/logger.js +38 -0
- package/src/utils/serializer.js +44 -0
|
@@ -0,0 +1,446 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const BaseClient = require('./BaseClient');
|
|
4
|
+
const WorkflowRouter = require('./layers/WorkflowRouter');
|
|
5
|
+
const QueueManager = require('./layers/QueueManager');
|
|
6
|
+
const ForkJoinHandler = require('./layers/ForkJoinHandler');
|
|
7
|
+
const RPCHandler = require('./layers/RPCHandler');
|
|
8
|
+
const RetryHandler = require('./layers/RetryHandler');
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Main MQ client orchestrating all messaging operations
|
|
12
|
+
*
|
|
13
|
+
* @class ConnectorMQClient
|
|
14
|
+
* @extends BaseClient
|
|
15
|
+
*
|
|
16
|
+
* @example <caption>Basic Usage</caption>
|
|
17
|
+
* const mqClient = new ConnectorMQClient({
|
|
18
|
+
* url: 'amqp://localhost:5672',
|
|
19
|
+
* serviceName: 'invoice-service'
|
|
20
|
+
* });
|
|
21
|
+
*
|
|
22
|
+
* await mqClient.connect();
|
|
23
|
+
* await mqClient.publish('invoice.created', { id: 123 });
|
|
24
|
+
*
|
|
25
|
+
* @example <caption>With Workflow</caption>
|
|
26
|
+
* const mqClient = new ConnectorMQClient({
|
|
27
|
+
* url: 'amqp://localhost:5672',
|
|
28
|
+
* serviceName: 'invoice-service',
|
|
29
|
+
* enableRPC: true
|
|
30
|
+
* });
|
|
31
|
+
*/
|
|
32
|
+
class ConnectorMQClient extends BaseClient {
|
|
33
|
+
/**
|
|
34
|
+
* Creates a new ConnectorMQClient instance
|
|
35
|
+
*
|
|
36
|
+
* @constructor
|
|
37
|
+
* @param {Object} [config={}] - Configuration options
|
|
38
|
+
* @param {string} config.url - RabbitMQ connection URL
|
|
39
|
+
* @param {string} [config.serviceName='unknown'] - Service name
|
|
40
|
+
* @param {boolean} [config.enableRPC=true] - Enable RPC handler
|
|
41
|
+
* @param {number} [config.prefetchCount=10] - Message prefetch count
|
|
42
|
+
* @param {Object} [config.retry] - Retry configuration
|
|
43
|
+
*
|
|
44
|
+
* @example
|
|
45
|
+
* const mqClient = new ConnectorMQClient({
|
|
46
|
+
* url: 'amqp://user:pass@localhost:5672',
|
|
47
|
+
* serviceName: 'my-service',
|
|
48
|
+
* prefetchCount: 20
|
|
49
|
+
* });
|
|
50
|
+
*/
|
|
51
|
+
constructor(config = {}) {
|
|
52
|
+
super(config);
|
|
53
|
+
|
|
54
|
+
// Initialize layers
|
|
55
|
+
this.workflow = new WorkflowRouter(this, config);
|
|
56
|
+
this.queues = new QueueManager(this, config);
|
|
57
|
+
this.retry = new RetryHandler(this, config);
|
|
58
|
+
this.forkJoin = new ForkJoinHandler(this, this.queues, config);
|
|
59
|
+
this.rpc = new RPCHandler(this, this.queues, config);
|
|
60
|
+
|
|
61
|
+
// Service identification
|
|
62
|
+
this.serviceName = config.serviceName || 'unknown';
|
|
63
|
+
|
|
64
|
+
// Track initialization state
|
|
65
|
+
this._initialized = false;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Connect to RabbitMQ and initialize layers
|
|
70
|
+
*
|
|
71
|
+
* @async
|
|
72
|
+
* @method connect
|
|
73
|
+
* @returns {Promise<boolean>} Connection success
|
|
74
|
+
*
|
|
75
|
+
* @throws {Error} If connection fails
|
|
76
|
+
*
|
|
77
|
+
* @example
|
|
78
|
+
* try {
|
|
79
|
+
* await mqClient.connect();
|
|
80
|
+
* console.log('Connected to RabbitMQ');
|
|
81
|
+
* } catch (error) {
|
|
82
|
+
* console.error('Connection failed:', error);
|
|
83
|
+
* }
|
|
84
|
+
*/
|
|
85
|
+
async connect() {
|
|
86
|
+
// Base connection
|
|
87
|
+
await super.connect();
|
|
88
|
+
|
|
89
|
+
// Initialize RPC handler if needed
|
|
90
|
+
if (this._config.enableRPC !== false) {
|
|
91
|
+
await this.rpc.initialize();
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Setup service queues if service name provided
|
|
95
|
+
if (this.serviceName !== 'unknown') {
|
|
96
|
+
try {
|
|
97
|
+
await this.queues.setupServiceQueues(this.serviceName);
|
|
98
|
+
} catch (error) {
|
|
99
|
+
console.warn(`Failed to setup service queues: ${error.message}`);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
this._initialized = true;
|
|
104
|
+
return true;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Disconnect from RabbitMQ with cleanup
|
|
109
|
+
*
|
|
110
|
+
* @async
|
|
111
|
+
* @method disconnect
|
|
112
|
+
* @returns {Promise<void>}
|
|
113
|
+
*
|
|
114
|
+
* @example
|
|
115
|
+
* await mqClient.disconnect();
|
|
116
|
+
*/
|
|
117
|
+
async disconnect() {
|
|
118
|
+
if (this._initialized) {
|
|
119
|
+
// Cleanup layers
|
|
120
|
+
await this.forkJoin.cleanupAll();
|
|
121
|
+
await this.rpc.cleanup();
|
|
122
|
+
await this.queues.cleanup();
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// Base disconnect
|
|
126
|
+
await super.disconnect();
|
|
127
|
+
|
|
128
|
+
this._initialized = false;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// ============================================
|
|
132
|
+
// Workflow Operations (via WorkflowRouter)
|
|
133
|
+
// ============================================
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Publish workflow to initialization queue
|
|
137
|
+
*
|
|
138
|
+
* @async
|
|
139
|
+
* @method publishWorkflowInit
|
|
140
|
+
* @param {Object} workflow - Workflow definition
|
|
141
|
+
* @param {Object} [options] - Publishing options
|
|
142
|
+
* @returns {Promise<boolean>} Publish success
|
|
143
|
+
*
|
|
144
|
+
* @example
|
|
145
|
+
* await mqClient.publishWorkflowInit({
|
|
146
|
+
* cookbook: cookbookDef,
|
|
147
|
+
* context: { invoiceId: 123 }
|
|
148
|
+
* });
|
|
149
|
+
*/
|
|
150
|
+
async publishWorkflowInit(workflow, options) {
|
|
151
|
+
return this.workflow.publishWorkflowInit(workflow, options);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Publish message to service workflow queue
|
|
156
|
+
*
|
|
157
|
+
* @async
|
|
158
|
+
* @method publishToServiceWorkflow
|
|
159
|
+
* @param {string} serviceName - Target service name
|
|
160
|
+
* @param {Object} message - Message to send
|
|
161
|
+
* @param {Object} [options] - Publishing options
|
|
162
|
+
* @returns {Promise<boolean>} Publish success
|
|
163
|
+
*
|
|
164
|
+
* @example
|
|
165
|
+
* await mqClient.publishToServiceWorkflow(
|
|
166
|
+
* 'invoice-service',
|
|
167
|
+
* { action: 'process', data: {...} }
|
|
168
|
+
* );
|
|
169
|
+
*/
|
|
170
|
+
async publishToServiceWorkflow(serviceName, message, options) {
|
|
171
|
+
return this.workflow.publishToServiceWorkflow(serviceName, message, options);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Publish message directly to service queue
|
|
176
|
+
*
|
|
177
|
+
* @async
|
|
178
|
+
* @method publishToService
|
|
179
|
+
* @param {string} serviceName - Target service name
|
|
180
|
+
* @param {Object} message - Message to send
|
|
181
|
+
* @param {Object} [options] - Publishing options
|
|
182
|
+
* @returns {Promise<boolean>} Publish success
|
|
183
|
+
*
|
|
184
|
+
* @example
|
|
185
|
+
* await mqClient.publishToService(
|
|
186
|
+
* 'email-service',
|
|
187
|
+
* { template: 'invoice', data: {...} }
|
|
188
|
+
* );
|
|
189
|
+
*/
|
|
190
|
+
async publishToService(serviceName, message, options) {
|
|
191
|
+
return this.workflow.publishToService(serviceName, message, options);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Publish workflow completed
|
|
196
|
+
*/
|
|
197
|
+
async publishWorkflowCompleted(result, options) {
|
|
198
|
+
return this.workflow.publishWorkflowCompleted(result, options);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Route to next service in workflow
|
|
203
|
+
*/
|
|
204
|
+
async routeToNextService(workflow, nextService, stepResult) {
|
|
205
|
+
return this.workflow.routeToNextService(workflow, nextService, stepResult);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Consume from workflow init queue
|
|
210
|
+
*/
|
|
211
|
+
async consumeWorkflowInit(handler, options) {
|
|
212
|
+
return this.workflow.consumeWorkflowInit(handler, options);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Consume from service workflow queue
|
|
217
|
+
*/
|
|
218
|
+
async consumeServiceWorkflow(serviceName, handler, options) {
|
|
219
|
+
return this.workflow.consumeServiceWorkflow(serviceName, handler, options);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// ============================================
|
|
223
|
+
// Queue Management (via QueueManager)
|
|
224
|
+
// ============================================
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Ensure queue exists with configuration
|
|
228
|
+
*/
|
|
229
|
+
async ensureQueue(queueName, options) {
|
|
230
|
+
return this.queues.ensureQueue(queueName, options);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* Setup service queues
|
|
235
|
+
*/
|
|
236
|
+
async setupServiceQueues(serviceName, options) {
|
|
237
|
+
return this.queues.setupServiceQueues(serviceName || this.serviceName, options);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* Create temporary queue
|
|
242
|
+
*/
|
|
243
|
+
async createTemporaryQueue(prefix, options) {
|
|
244
|
+
return this.queues.createTemporaryQueue(prefix, options);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* Get queue statistics
|
|
249
|
+
*/
|
|
250
|
+
async getQueueStats(queueName) {
|
|
251
|
+
return this.queues.getQueueStats(queueName);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
// ============================================
|
|
255
|
+
// Fork-Join Operations (via ForkJoinHandler)
|
|
256
|
+
// ============================================
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* Execute fork-join pattern
|
|
260
|
+
*/
|
|
261
|
+
async forkJoin(branches, joinStrategy, options) {
|
|
262
|
+
return this.forkJoin.forkJoin(branches, joinStrategy, options);
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* Fork work to multiple queues
|
|
267
|
+
*/
|
|
268
|
+
async fork(branches, context) {
|
|
269
|
+
return this.forkJoin.fork(branches, context);
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
/**
|
|
273
|
+
* Create accumulator for collecting results
|
|
274
|
+
*/
|
|
275
|
+
async createAccumulator(workflowId, stepId, expectedCount) {
|
|
276
|
+
return this.forkJoin.createAccumulator(workflowId, stepId, expectedCount);
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
/**
|
|
280
|
+
* Join results with strategy
|
|
281
|
+
*/
|
|
282
|
+
async join(queueName, joinStrategy, options) {
|
|
283
|
+
return this.forkJoin.join(queueName, joinStrategy, options);
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
// ============================================
|
|
287
|
+
// RPC Operations (via RPCHandler)
|
|
288
|
+
// ============================================
|
|
289
|
+
|
|
290
|
+
/**
|
|
291
|
+
* Make RPC call
|
|
292
|
+
*/
|
|
293
|
+
async rpcCall(targetQueue, request, options) {
|
|
294
|
+
return this.rpc.call(targetQueue, request, options);
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
/**
|
|
298
|
+
* Setup RPC server
|
|
299
|
+
*/
|
|
300
|
+
async rpcServe(queue, handler, options) {
|
|
301
|
+
return this.rpc.serve(queue, handler, options);
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
/**
|
|
305
|
+
* Make multiple RPC calls
|
|
306
|
+
*/
|
|
307
|
+
async rpcCallMany(requests) {
|
|
308
|
+
return this.rpc.callMany(requests);
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
/**
|
|
312
|
+
* RPC with retry
|
|
313
|
+
*/
|
|
314
|
+
async rpcCallWithRetry(targetQueue, request, options) {
|
|
315
|
+
return this.rpc.callWithRetry(targetQueue, request, options);
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
// ============================================
|
|
319
|
+
// Retry Operations (via RetryHandler)
|
|
320
|
+
// ============================================
|
|
321
|
+
|
|
322
|
+
/**
|
|
323
|
+
* Consume with automatic retry
|
|
324
|
+
*/
|
|
325
|
+
async consumeWithRetry(queue, handler, options) {
|
|
326
|
+
return this.retry.consumeWithRetry(queue, handler, options);
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
/**
|
|
330
|
+
* Process message with retry logic
|
|
331
|
+
*/
|
|
332
|
+
async processWithRetry(handler, message, rawMsg, options) {
|
|
333
|
+
return this.retry.processWithRetry(handler, message, rawMsg, options);
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
/**
|
|
337
|
+
* Send message to DLQ
|
|
338
|
+
*/
|
|
339
|
+
async publishToDLQ(originalQueue, message, error, options) {
|
|
340
|
+
return this.retry.sendToDLQ(message, originalQueue, error, options);
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
/**
|
|
344
|
+
* Process DLQ messages
|
|
345
|
+
*/
|
|
346
|
+
async processDLQ(dlqName, handler, options) {
|
|
347
|
+
return this.retry.processDLQ(dlqName, handler, options);
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
/**
|
|
351
|
+
* Get retry statistics
|
|
352
|
+
*/
|
|
353
|
+
getRetryStats() {
|
|
354
|
+
return this.retry.getStats();
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
// ============================================
|
|
358
|
+
// Convenience Methods
|
|
359
|
+
// ============================================
|
|
360
|
+
|
|
361
|
+
/**
|
|
362
|
+
* Publish with routing (decides between workflow/service/direct)
|
|
363
|
+
*/
|
|
364
|
+
async publishWithRouting(message, options = {}) {
|
|
365
|
+
if (options.workflow) {
|
|
366
|
+
return this.publishWorkflowInit(message, options);
|
|
367
|
+
} else if (options.service) {
|
|
368
|
+
return this.publishToService(options.service, message, options);
|
|
369
|
+
} else if (options.rpc) {
|
|
370
|
+
return this.rpcCall(options.rpc, message, options);
|
|
371
|
+
} else {
|
|
372
|
+
return this.publish(message, options);
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
/**
|
|
377
|
+
* Smart consume (with retry and error handling)
|
|
378
|
+
*/
|
|
379
|
+
async smartConsume(queue, handler, options = {}) {
|
|
380
|
+
const wrappedHandler = async (message, rawMsg) => {
|
|
381
|
+
// Add context
|
|
382
|
+
message._context = {
|
|
383
|
+
queue,
|
|
384
|
+
service: this.serviceName,
|
|
385
|
+
receivedAt: Date.now()
|
|
386
|
+
};
|
|
387
|
+
|
|
388
|
+
// Process with retry if enabled
|
|
389
|
+
if (options.retry !== false) {
|
|
390
|
+
return this.processWithRetry(handler, message, rawMsg, options);
|
|
391
|
+
} else {
|
|
392
|
+
return handler(message, rawMsg);
|
|
393
|
+
}
|
|
394
|
+
};
|
|
395
|
+
|
|
396
|
+
return this.consume(wrappedHandler, { queue, ...options });
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
/**
|
|
400
|
+
* Get overall health status
|
|
401
|
+
*/
|
|
402
|
+
async getHealth() {
|
|
403
|
+
const health = {
|
|
404
|
+
connected: this.isConnected(),
|
|
405
|
+
initialized: this._initialized,
|
|
406
|
+
service: this.serviceName,
|
|
407
|
+
layers: {
|
|
408
|
+
workflow: true,
|
|
409
|
+
queues: true,
|
|
410
|
+
retry: true,
|
|
411
|
+
forkJoin: true,
|
|
412
|
+
rpc: this.rpc.getPendingCount() >= 0
|
|
413
|
+
},
|
|
414
|
+
stats: {
|
|
415
|
+
retry: this.retry.getStats(),
|
|
416
|
+
pendingRPC: this.rpc.getPendingCount(),
|
|
417
|
+
managedQueues: this.queues.getManagedQueues().length
|
|
418
|
+
}
|
|
419
|
+
};
|
|
420
|
+
|
|
421
|
+
// Try to get queue stats if connected
|
|
422
|
+
if (this.isConnected() && this.serviceName !== 'unknown') {
|
|
423
|
+
try {
|
|
424
|
+
health.queueStats = await this.getQueueStats(`${this.serviceName}.queue`);
|
|
425
|
+
} catch (error) {
|
|
426
|
+
health.queueStats = { error: error.message };
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
return health;
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
/**
|
|
434
|
+
* Static factory method for quick setup
|
|
435
|
+
*/
|
|
436
|
+
static async create(config) {
|
|
437
|
+
const client = new ConnectorMQClient(config);
|
|
438
|
+
await client.connect();
|
|
439
|
+
return client;
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
// Export join strategies for convenience
|
|
444
|
+
ConnectorMQClient.JoinStrategies = ForkJoinHandler.JoinStrategies;
|
|
445
|
+
|
|
446
|
+
module.exports = ConnectorMQClient;
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* configSchema.js
|
|
5
|
+
*
|
|
6
|
+
* JSON Schema used by Ajv to validate the user-supplied configuration object.
|
|
7
|
+
* Ensures required fields are present and correctly typed. Any unsupported
|
|
8
|
+
* or misspelled field will trigger a ValidationError.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
module.exports = {
|
|
12
|
+
type: 'object',
|
|
13
|
+
properties: {
|
|
14
|
+
type: {
|
|
15
|
+
type: 'string',
|
|
16
|
+
enum: ['rabbitmq'],
|
|
17
|
+
},
|
|
18
|
+
host: {
|
|
19
|
+
type: 'string',
|
|
20
|
+
minLength: 1,
|
|
21
|
+
},
|
|
22
|
+
// For RabbitMQ: queue is required.
|
|
23
|
+
queue: {
|
|
24
|
+
type: 'string',
|
|
25
|
+
minLength: 1,
|
|
26
|
+
},
|
|
27
|
+
exchange: {
|
|
28
|
+
type: 'string',
|
|
29
|
+
},
|
|
30
|
+
durable: {
|
|
31
|
+
type: 'boolean',
|
|
32
|
+
},
|
|
33
|
+
prefetch: {
|
|
34
|
+
type: 'integer',
|
|
35
|
+
minimum: 0,
|
|
36
|
+
},
|
|
37
|
+
noAck: {
|
|
38
|
+
type: 'boolean',
|
|
39
|
+
},
|
|
40
|
+
logger: {
|
|
41
|
+
type: 'object',
|
|
42
|
+
description: 'Custom logger with methods: info, warn, error, debug',
|
|
43
|
+
},
|
|
44
|
+
retryPolicy: {
|
|
45
|
+
type: 'object',
|
|
46
|
+
properties: {
|
|
47
|
+
retries: {
|
|
48
|
+
type: 'integer',
|
|
49
|
+
minimum: 0,
|
|
50
|
+
},
|
|
51
|
+
initialDelayMs: {
|
|
52
|
+
type: 'integer',
|
|
53
|
+
minimum: 0,
|
|
54
|
+
},
|
|
55
|
+
maxDelayMs: {
|
|
56
|
+
type: 'integer',
|
|
57
|
+
minimum: 0,
|
|
58
|
+
},
|
|
59
|
+
factor: {
|
|
60
|
+
type: 'number',
|
|
61
|
+
minimum: 1,
|
|
62
|
+
},
|
|
63
|
+
},
|
|
64
|
+
required: ['retries', 'initialDelayMs', 'maxDelayMs', 'factor'],
|
|
65
|
+
additionalProperties: false,
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
required: ['type', 'host', 'queue'],
|
|
69
|
+
additionalProperties: false,
|
|
70
|
+
};
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* defaultConfig.js
|
|
5
|
+
*
|
|
6
|
+
* Provides default configuration values for AgentMQClient.
|
|
7
|
+
* Users can override any of these by passing a custom config object
|
|
8
|
+
* or by supplying overrides to connect().
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
module.exports = {
|
|
12
|
+
// Transport type: currently only 'rabbitmq' is fully supported.
|
|
13
|
+
type: 'rabbitmq',
|
|
14
|
+
|
|
15
|
+
// RabbitMQ connection URI or hostname (e.g., 'amqp://localhost:5672').
|
|
16
|
+
host: 'amqp://localhost:5672',
|
|
17
|
+
|
|
18
|
+
// Default queue name; can be overridden per call to publish/consume.
|
|
19
|
+
queue: '',
|
|
20
|
+
|
|
21
|
+
// Default exchange name (empty string → default direct exchange).
|
|
22
|
+
exchange: '',
|
|
23
|
+
|
|
24
|
+
// Declare queues/exchanges as durable by default.
|
|
25
|
+
durable: true,
|
|
26
|
+
|
|
27
|
+
// Default prefetch count for consumers.
|
|
28
|
+
prefetch: 1,
|
|
29
|
+
|
|
30
|
+
// Default auto-acknowledge setting for consumers.
|
|
31
|
+
noAck: false,
|
|
32
|
+
|
|
33
|
+
// Custom logger object (if not provided, console.* will be used).
|
|
34
|
+
// Expected interface: { info(), warn(), error(), debug() }.
|
|
35
|
+
logger: null,
|
|
36
|
+
|
|
37
|
+
// Retry policy for reconnect attempts (not fully implemented in current version).
|
|
38
|
+
// - retries: maximum number of reconnection attempts
|
|
39
|
+
// - initialDelayMs: starting backoff delay
|
|
40
|
+
// - maxDelayMs: maximum backoff delay
|
|
41
|
+
// - factor: exponential backoff multiplier
|
|
42
|
+
retryPolicy: {
|
|
43
|
+
retries: 5,
|
|
44
|
+
initialDelayMs: 1000,
|
|
45
|
+
maxDelayMs: 30000,
|
|
46
|
+
factor: 2,
|
|
47
|
+
},
|
|
48
|
+
};
|
package/src/index.js
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @module @onlineapps/conn-infra-mq
|
|
5
|
+
* @description RabbitMQ connector with workflow routing, fork-join, RPC, and retry patterns for OA Drive.
|
|
6
|
+
* Provides layered architecture for complex messaging patterns.
|
|
7
|
+
*
|
|
8
|
+
* @see {@link https://github.com/onlineapps/oa-drive/tree/main/shared/connector/conn-infra-mq|GitHub Repository}
|
|
9
|
+
* @author OA Drive Team
|
|
10
|
+
* @license MIT
|
|
11
|
+
* @since 1.0.0
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
const ConnectorMQClient = require('./ConnectorMQClient');
|
|
15
|
+
const BaseClient = require('./BaseClient');
|
|
16
|
+
|
|
17
|
+
// Layers - exported for advanced usage
|
|
18
|
+
const WorkflowRouter = require('./layers/WorkflowRouter');
|
|
19
|
+
const QueueManager = require('./layers/QueueManager');
|
|
20
|
+
const ForkJoinHandler = require('./layers/ForkJoinHandler');
|
|
21
|
+
const RPCHandler = require('./layers/RPCHandler');
|
|
22
|
+
const RetryHandler = require('./layers/RetryHandler');
|
|
23
|
+
|
|
24
|
+
// Default export - the main client
|
|
25
|
+
module.exports = ConnectorMQClient;
|
|
26
|
+
|
|
27
|
+
// Named exports
|
|
28
|
+
module.exports.ConnectorMQClient = ConnectorMQClient;
|
|
29
|
+
module.exports.BaseClient = BaseClient;
|
|
30
|
+
|
|
31
|
+
// Export layers for advanced usage
|
|
32
|
+
module.exports.layers = {
|
|
33
|
+
WorkflowRouter,
|
|
34
|
+
QueueManager,
|
|
35
|
+
ForkJoinHandler,
|
|
36
|
+
RPCHandler,
|
|
37
|
+
RetryHandler
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
// Backwards compatibility - MQWrapper points to ConnectorMQClient
|
|
41
|
+
module.exports.MQWrapper = ConnectorMQClient;
|
|
42
|
+
|
|
43
|
+
// Export join strategies
|
|
44
|
+
module.exports.JoinStrategies = ForkJoinHandler.JoinStrategies;
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Factory function to create MQ client instance
|
|
48
|
+
*
|
|
49
|
+
* @function create
|
|
50
|
+
* @param {Object} config - Configuration object
|
|
51
|
+
* @returns {ConnectorMQClient} New MQ client instance
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* const mqClient = create({
|
|
55
|
+
* url: 'amqp://localhost:5672',
|
|
56
|
+
* serviceName: 'invoice-service'
|
|
57
|
+
* });
|
|
58
|
+
*/
|
|
59
|
+
module.exports.create = ConnectorMQClient.create;
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Current version
|
|
63
|
+
* @constant {string}
|
|
64
|
+
*/
|
|
65
|
+
module.exports.VERSION = '1.0.0';
|