@onlineapps/conn-infra-mq 1.1.10 → 1.1.12
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 +20 -1
- package/package.json +2 -1
- package/src/ConnectorMQClient.js +1 -1
- package/src/config/configSchema.js +1 -1
- package/src/index.js +1 -1
- package/src/layers/QueueManager.js +64 -19
- package/src/layers/WorkflowRouter.js +14 -28
- package/src/BaseClient.js +0 -219
package/README.md
CHANGED
|
@@ -38,7 +38,7 @@ yarn add @onlineapps/conn-infra-mq
|
|
|
38
38
|
## 🏗️ Architecture
|
|
39
39
|
|
|
40
40
|
```
|
|
41
|
-
ConnectorMQClient (main orchestrator)
|
|
41
|
+
ConnectorMQClient (main orchestrator - for business services only)
|
|
42
42
|
├── BaseClient (core AMQP operations)
|
|
43
43
|
├── WorkflowRouter (workflow orchestration)
|
|
44
44
|
├── QueueManager (queue lifecycle management)
|
|
@@ -47,6 +47,25 @@ ConnectorMQClient (main orchestrator)
|
|
|
47
47
|
└── RetryHandler (error recovery & DLQ)
|
|
48
48
|
```
|
|
49
49
|
|
|
50
|
+
### WorkflowRouter - How It Works
|
|
51
|
+
|
|
52
|
+
**Purpose**: Handles workflow routing between services in a decentralized architecture.
|
|
53
|
+
|
|
54
|
+
**Key Methods**:
|
|
55
|
+
- `publishWorkflowInit(workflow, options)` - Publishes workflow to `workflow.init` queue (entry point)
|
|
56
|
+
- `publishToServiceWorkflow(serviceName, message, options)` - Routes to specific service's workflow queue
|
|
57
|
+
- `publishWorkflowCompleted(result, options)` - Publishes completed workflow to `workflow.completed` queue
|
|
58
|
+
- `consumeWorkflowInit(handler, options)` - Consumes from `workflow.init` (competing consumers pattern)
|
|
59
|
+
- `consumeServiceWorkflow(serviceName, handler, options)` - Consumes from service-specific workflow queue
|
|
60
|
+
|
|
61
|
+
**How It Works**:
|
|
62
|
+
1. **Gateway** publishes to `workflow.init` via `publishWorkflowInit()`
|
|
63
|
+
2. **Business services** (competing consumers) consume from `workflow.init` via `consumeWorkflowInit()`
|
|
64
|
+
3. **Services** route to next service via `publishToServiceWorkflow()`
|
|
65
|
+
4. **Final service** publishes completion via `publishWorkflowCompleted()`
|
|
66
|
+
|
|
67
|
+
**Note**: WorkflowRouter is part of `conn-infra-mq` connector (for business services). Infrastructure services (gateway) should use the underlying MQ client library directly, not the connector.
|
|
68
|
+
|
|
50
69
|
## 🔧 Quick Start
|
|
51
70
|
|
|
52
71
|
```js
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@onlineapps/conn-infra-mq",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.12",
|
|
4
4
|
"description": "A promise-based, broker-agnostic client for sending and receiving messages via RabbitMQ",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"repository": {
|
|
@@ -42,6 +42,7 @@
|
|
|
42
42
|
},
|
|
43
43
|
"homepage": "https://github.com/onlineapps/connector-mq-client#readme",
|
|
44
44
|
"dependencies": {
|
|
45
|
+
"@onlineapps/mq-client-core": "^1.0.0",
|
|
45
46
|
"ajv": "^8.11.0",
|
|
46
47
|
"amqplib": "^0.10.3",
|
|
47
48
|
"lodash.merge": "^4.6.2"
|
package/src/ConnectorMQClient.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const BaseClient = require('
|
|
3
|
+
const BaseClient = require('@onlineapps/mq-client-core');
|
|
4
4
|
const WorkflowRouter = require('./layers/WorkflowRouter');
|
|
5
5
|
const QueueManager = require('./layers/QueueManager');
|
|
6
6
|
const ForkJoinHandler = require('./layers/ForkJoinHandler');
|
package/src/index.js
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
14
|
const ConnectorMQClient = require('./ConnectorMQClient');
|
|
15
|
-
const BaseClient = require('
|
|
15
|
+
const BaseClient = require('@onlineapps/mq-client-core');
|
|
16
16
|
|
|
17
17
|
// Layers - exported for advanced usage
|
|
18
18
|
const WorkflowRouter = require('./layers/WorkflowRouter');
|
|
@@ -80,8 +80,23 @@ class QueueManager {
|
|
|
80
80
|
// Track managed queue
|
|
81
81
|
this.managedQueues.add(queueName);
|
|
82
82
|
|
|
83
|
-
//
|
|
84
|
-
|
|
83
|
+
// Use checkQueue first to avoid 406 PRECONDITION-FAILED closing the channel
|
|
84
|
+
// If queue doesn't exist (404), then assertQueue to create it
|
|
85
|
+
try {
|
|
86
|
+
await channel.checkQueue(queueName);
|
|
87
|
+
// Queue exists - return queue info
|
|
88
|
+
return channel.checkQueue(queueName);
|
|
89
|
+
} catch (checkErr) {
|
|
90
|
+
// If queue doesn't exist (404), create it with provided options
|
|
91
|
+
if (checkErr.code === 404) {
|
|
92
|
+
return channel.assertQueue(queueName, queueOptions);
|
|
93
|
+
} else {
|
|
94
|
+
// Other error (including 406) - queue exists with different args
|
|
95
|
+
// Log warning and return queue info without asserting
|
|
96
|
+
console.warn(`[QueueManager] Queue ${queueName} exists with different arguments, using as-is:`, checkErr.message);
|
|
97
|
+
return channel.checkQueue(queueName);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
85
100
|
}
|
|
86
101
|
|
|
87
102
|
/**
|
|
@@ -154,30 +169,60 @@ class QueueManager {
|
|
|
154
169
|
const queues = {};
|
|
155
170
|
|
|
156
171
|
// Create main processing queue
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
172
|
+
// Handle PRECONDITION-FAILED gracefully - queue may exist with different args
|
|
173
|
+
try {
|
|
174
|
+
await this.ensureQueue(`${serviceName}.queue`, {
|
|
175
|
+
ttl: options.ttl || this.config.defaultTTL,
|
|
176
|
+
dlq: true,
|
|
177
|
+
durable: true,
|
|
178
|
+
maxRetries: this.config.maxRetries
|
|
179
|
+
});
|
|
180
|
+
} catch (error) {
|
|
181
|
+
if (error.code === 406) {
|
|
182
|
+
// Queue exists with different arguments - use it as-is
|
|
183
|
+
console.warn(`[QueueManager] Queue ${serviceName}.queue exists with different arguments, using as-is`);
|
|
184
|
+
// Verify queue exists
|
|
185
|
+
await channel.checkQueue(`${serviceName}.queue`);
|
|
186
|
+
} else {
|
|
187
|
+
throw error;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
163
190
|
queues.main = `${serviceName}.queue`;
|
|
164
191
|
|
|
165
192
|
// Create dead letter queue
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
193
|
+
try {
|
|
194
|
+
await this.ensureQueue(`${serviceName}.dlq`, {
|
|
195
|
+
ttl: null, // No TTL for DLQ
|
|
196
|
+
dlq: false,
|
|
197
|
+
durable: true,
|
|
198
|
+
autoDelete: false
|
|
199
|
+
});
|
|
200
|
+
} catch (error) {
|
|
201
|
+
if (error.code === 406) {
|
|
202
|
+
console.warn(`[QueueManager] Queue ${serviceName}.dlq exists with different arguments, using as-is`);
|
|
203
|
+
await channel.checkQueue(`${serviceName}.dlq`);
|
|
204
|
+
} else {
|
|
205
|
+
throw error;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
172
208
|
queues.dlq = `${serviceName}.dlq`;
|
|
173
209
|
|
|
174
210
|
// Create workflow queue if requested
|
|
175
211
|
if (options.includeWorkflow !== false) {
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
212
|
+
try {
|
|
213
|
+
await this.ensureQueue(`${serviceName}.workflow`, {
|
|
214
|
+
ttl: options.workflowTTL || this.config.defaultTTL,
|
|
215
|
+
dlq: true,
|
|
216
|
+
durable: true
|
|
217
|
+
});
|
|
218
|
+
} catch (error) {
|
|
219
|
+
if (error.code === 406) {
|
|
220
|
+
console.warn(`[QueueManager] Queue ${serviceName}.workflow exists with different arguments, using as-is`);
|
|
221
|
+
await channel.checkQueue(`${serviceName}.workflow`);
|
|
222
|
+
} else {
|
|
223
|
+
throw error;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
181
226
|
queues.workflow = `${serviceName}.workflow`;
|
|
182
227
|
}
|
|
183
228
|
|
|
@@ -21,10 +21,8 @@ class WorkflowRouter {
|
|
|
21
21
|
* @param {Object} options - Additional publish options
|
|
22
22
|
*/
|
|
23
23
|
async publishWorkflowInit(workflow, options = {}) {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
...options
|
|
27
|
-
});
|
|
24
|
+
// BaseClient.publish expects: publish(queue, message, options)
|
|
25
|
+
return this.client.publish(this.config.workflowInitQueue, workflow, options);
|
|
28
26
|
}
|
|
29
27
|
|
|
30
28
|
/**
|
|
@@ -34,10 +32,8 @@ class WorkflowRouter {
|
|
|
34
32
|
* @param {Object} options - Additional publish options
|
|
35
33
|
*/
|
|
36
34
|
async publishToServiceWorkflow(serviceName, message, options = {}) {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
...options
|
|
40
|
-
});
|
|
35
|
+
// BaseClient.publish expects: publish(queue, message, options)
|
|
36
|
+
return this.client.publish(`${serviceName}.workflow`, message, options);
|
|
41
37
|
}
|
|
42
38
|
|
|
43
39
|
/**
|
|
@@ -47,10 +43,8 @@ class WorkflowRouter {
|
|
|
47
43
|
* @param {Object} options - Additional publish options
|
|
48
44
|
*/
|
|
49
45
|
async publishToService(serviceName, message, options = {}) {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
...options
|
|
53
|
-
});
|
|
46
|
+
// BaseClient.publish expects: publish(queue, message, options)
|
|
47
|
+
return this.client.publish(`${serviceName}.queue`, message, options);
|
|
54
48
|
}
|
|
55
49
|
|
|
56
50
|
/**
|
|
@@ -59,10 +53,8 @@ class WorkflowRouter {
|
|
|
59
53
|
* @param {Object} options - Additional publish options
|
|
60
54
|
*/
|
|
61
55
|
async publishWorkflowCompleted(result, options = {}) {
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
...options
|
|
65
|
-
});
|
|
56
|
+
// BaseClient.publish expects: publish(queue, message, options)
|
|
57
|
+
return this.client.publish(this.config.workflowCompletedQueue, result, options);
|
|
66
58
|
}
|
|
67
59
|
|
|
68
60
|
/**
|
|
@@ -95,10 +87,8 @@ class WorkflowRouter {
|
|
|
95
87
|
* @param {Object} options - Consume options
|
|
96
88
|
*/
|
|
97
89
|
async consumeWorkflowInit(handler, options = {}) {
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
...options
|
|
101
|
-
});
|
|
90
|
+
// BaseClient.consume expects: consume(queue, handler, options)
|
|
91
|
+
return this.client.consume(this.config.workflowInitQueue, handler, options);
|
|
102
92
|
}
|
|
103
93
|
|
|
104
94
|
/**
|
|
@@ -114,10 +104,8 @@ class WorkflowRouter {
|
|
|
114
104
|
serviceName = this.config.serviceName;
|
|
115
105
|
}
|
|
116
106
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
...options
|
|
120
|
-
});
|
|
107
|
+
// BaseClient.consume expects: consume(queue, handler, options)
|
|
108
|
+
return this.client.consume(`${serviceName}.workflow`, handler, options);
|
|
121
109
|
}
|
|
122
110
|
|
|
123
111
|
/**
|
|
@@ -126,10 +114,8 @@ class WorkflowRouter {
|
|
|
126
114
|
* @param {Object} options - Consume options
|
|
127
115
|
*/
|
|
128
116
|
async consumeWorkflowCompleted(handler, options = {}) {
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
...options
|
|
132
|
-
});
|
|
117
|
+
// BaseClient.consume expects: consume(queue, handler, options)
|
|
118
|
+
return this.client.consume(this.config.workflowCompletedQueue, handler, options);
|
|
133
119
|
}
|
|
134
120
|
}
|
|
135
121
|
|
package/src/BaseClient.js
DELETED
|
@@ -1,219 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* ConnectorMQClient: a promise-based, broker-agnostic client for RabbitMQ
|
|
5
|
-
* Uses transportFactory to select the appropriate transport implementation.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
const Ajv = require('ajv');
|
|
9
|
-
const merge = require('lodash.merge');
|
|
10
|
-
|
|
11
|
-
const configSchema = require('./config/configSchema');
|
|
12
|
-
const defaultConfig = require('./config/defaultConfig');
|
|
13
|
-
const transportFactory = require('./transports/transportFactory');
|
|
14
|
-
const serializer = require('./utils/serializer');
|
|
15
|
-
const {
|
|
16
|
-
ConnectionError,
|
|
17
|
-
PublishError,
|
|
18
|
-
ConsumeError,
|
|
19
|
-
ValidationError,
|
|
20
|
-
SerializationError,
|
|
21
|
-
} = require('./utils/errorHandler');
|
|
22
|
-
|
|
23
|
-
class ConnectorMQClient {
|
|
24
|
-
/**
|
|
25
|
-
* @param {Object} config - User-supplied configuration.
|
|
26
|
-
* @throws {ValidationError} If required fields are missing or invalid.
|
|
27
|
-
*/
|
|
28
|
-
constructor(config) {
|
|
29
|
-
const ajv = new Ajv({ allErrors: true, useDefaults: true });
|
|
30
|
-
const validate = ajv.compile(configSchema);
|
|
31
|
-
|
|
32
|
-
// Merge user config with defaults
|
|
33
|
-
this._config = merge({}, defaultConfig, config || {});
|
|
34
|
-
|
|
35
|
-
// Validate merged config
|
|
36
|
-
const valid = validate(this._config);
|
|
37
|
-
if (!valid) {
|
|
38
|
-
const details = validate.errors.map((err) => ({
|
|
39
|
-
path: err.instancePath,
|
|
40
|
-
message: err.message,
|
|
41
|
-
}));
|
|
42
|
-
throw new ValidationError('Invalid configuration', details);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
this._transport = null;
|
|
46
|
-
this._connected = false;
|
|
47
|
-
this._errorHandlers = [];
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* Connects to the message broker using merged configuration.
|
|
52
|
-
* @param {Object} [options] - Optional overrides for host, queue, etc.
|
|
53
|
-
* @returns {Promise<void>}
|
|
54
|
-
* @throws {ConnectionError} If connecting fails.
|
|
55
|
-
*/
|
|
56
|
-
async connect(options = {}) {
|
|
57
|
-
if (this._connected) return;
|
|
58
|
-
|
|
59
|
-
// Merge overrides into existing config
|
|
60
|
-
this._config = merge({}, this._config, options);
|
|
61
|
-
|
|
62
|
-
try {
|
|
63
|
-
// Instantiate appropriate transport: RabbitMQClient
|
|
64
|
-
this._transport = transportFactory.create(this._config);
|
|
65
|
-
|
|
66
|
-
// Register internal error propagation
|
|
67
|
-
this._transport.on('error', (err) => this._handleError(err));
|
|
68
|
-
|
|
69
|
-
await this._transport.connect(this._config);
|
|
70
|
-
this._connected = true;
|
|
71
|
-
} catch (err) {
|
|
72
|
-
throw new ConnectionError('Failed to connect to broker', err);
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
/**
|
|
77
|
-
* Disconnects from the message broker.
|
|
78
|
-
* @returns {Promise<void>}
|
|
79
|
-
* @throws {Error} If disconnecting fails unexpectedly.
|
|
80
|
-
*/
|
|
81
|
-
async disconnect() {
|
|
82
|
-
if (!this._connected || !this._transport) return;
|
|
83
|
-
try {
|
|
84
|
-
await this._transport.disconnect();
|
|
85
|
-
this._connected = false;
|
|
86
|
-
this._transport = null;
|
|
87
|
-
} catch (err) {
|
|
88
|
-
throw new Error(`Error during disconnect: ${err.message}`);
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
/**
|
|
93
|
-
* Publishes a message to the specified queue.
|
|
94
|
-
* @param {string} queue - Target queue name.
|
|
95
|
-
* @param {Object|Buffer|string} message - Payload to send.
|
|
96
|
-
* @param {Object} [options] - RabbitMQ-specific overrides (routingKey, persistent, headers).
|
|
97
|
-
* @returns {Promise<void>}
|
|
98
|
-
* @throws {ConnectionError} If not connected.
|
|
99
|
-
* @throws {PublishError} If publish fails.
|
|
100
|
-
*/
|
|
101
|
-
async publish(queue, message, options = {}) {
|
|
102
|
-
if (!this._connected || !this._transport) {
|
|
103
|
-
throw new ConnectionError('Cannot publish: client is not connected');
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
let buffer;
|
|
107
|
-
try {
|
|
108
|
-
if (Buffer.isBuffer(message)) {
|
|
109
|
-
buffer = message;
|
|
110
|
-
} else if (typeof message === 'string') {
|
|
111
|
-
buffer = Buffer.from(message, 'utf8');
|
|
112
|
-
} else {
|
|
113
|
-
const json = serializer.serialize(message);
|
|
114
|
-
buffer = Buffer.from(json, 'utf8');
|
|
115
|
-
}
|
|
116
|
-
} catch (err) {
|
|
117
|
-
throw new SerializationError('Failed to serialize message', message, err);
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
try {
|
|
121
|
-
await this._transport.publish(queue, buffer, options);
|
|
122
|
-
} catch (err) {
|
|
123
|
-
throw new PublishError(`Failed to publish to queue "${queue}"`, queue, err);
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
/**
|
|
128
|
-
* Begins consuming messages from the specified queue.
|
|
129
|
-
* @param {string} queue - Name of the queue to consume from.
|
|
130
|
-
* @param {function(Object): Promise<void>} messageHandler - Async function to process each message.
|
|
131
|
-
* @param {Object} [options] - RabbitMQ-specific overrides (prefetch, noAck).
|
|
132
|
-
* @returns {Promise<void>}
|
|
133
|
-
* @throws {ConnectionError} If not connected.
|
|
134
|
-
* @throws {ConsumeError} If consumer setup fails.
|
|
135
|
-
*/
|
|
136
|
-
async consume(queue, messageHandler, options = {}) {
|
|
137
|
-
if (!this._connected || !this._transport) {
|
|
138
|
-
throw new ConnectionError('Cannot consume: client is not connected');
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
// Apply prefetch and noAck overrides if provided
|
|
142
|
-
const { prefetch, noAck } = options;
|
|
143
|
-
const consumeOptions = {};
|
|
144
|
-
if (typeof prefetch === 'number') consumeOptions.prefetch = prefetch;
|
|
145
|
-
if (typeof noAck === 'boolean') consumeOptions.noAck = noAck;
|
|
146
|
-
|
|
147
|
-
try {
|
|
148
|
-
await this._transport.consume(
|
|
149
|
-
queue,
|
|
150
|
-
async (msg) => {
|
|
151
|
-
try {
|
|
152
|
-
await messageHandler(msg);
|
|
153
|
-
if (consumeOptions.noAck === false) {
|
|
154
|
-
await this.ack(msg);
|
|
155
|
-
}
|
|
156
|
-
} catch (handlerErr) {
|
|
157
|
-
// On handler error, nack with requeue: true
|
|
158
|
-
await this.nack(msg, { requeue: true });
|
|
159
|
-
}
|
|
160
|
-
},
|
|
161
|
-
consumeOptions
|
|
162
|
-
);
|
|
163
|
-
} catch (err) {
|
|
164
|
-
throw new ConsumeError(`Failed to start consumer for queue "${queue}"`, queue, err);
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
/**
|
|
169
|
-
* Acknowledges a RabbitMQ message.
|
|
170
|
-
* @param {Object} msg - RabbitMQ message object.
|
|
171
|
-
* @returns {Promise<void>}
|
|
172
|
-
*/
|
|
173
|
-
async ack(msg) {
|
|
174
|
-
if (!this._connected || !this._transport) {
|
|
175
|
-
throw new ConnectionError('Cannot ack: client is not connected');
|
|
176
|
-
}
|
|
177
|
-
return this._transport.ack(msg);
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
/**
|
|
181
|
-
* Negative-acknowledges a RabbitMQ message.
|
|
182
|
-
* @param {Object} msg - RabbitMQ message object.
|
|
183
|
-
* @param {Object} [options] - Options such as { requeue: boolean }.
|
|
184
|
-
* @returns {Promise<void>}
|
|
185
|
-
*/
|
|
186
|
-
async nack(msg, options = {}) {
|
|
187
|
-
if (!this._connected || !this._transport) {
|
|
188
|
-
throw new ConnectionError('Cannot nack: client is not connected');
|
|
189
|
-
}
|
|
190
|
-
return this._transport.nack(msg, options);
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
/**
|
|
194
|
-
* Registers a global error handler. Internal or transport-level errors will be forwarded here.
|
|
195
|
-
* @param {function(Error): void} callback
|
|
196
|
-
*/
|
|
197
|
-
onError(callback) {
|
|
198
|
-
if (typeof callback === 'function') {
|
|
199
|
-
this._errorHandlers.push(callback);
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
/**
|
|
204
|
-
* Internal helper to invoke all registered error handlers.
|
|
205
|
-
* @param {Error} error
|
|
206
|
-
* @private
|
|
207
|
-
*/
|
|
208
|
-
_handleError(error) {
|
|
209
|
-
this._errorHandlers.forEach((cb) => {
|
|
210
|
-
try {
|
|
211
|
-
cb(error);
|
|
212
|
-
} catch (_) {
|
|
213
|
-
// Ignore errors in user-provided error handlers
|
|
214
|
-
}
|
|
215
|
-
});
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
module.exports = ConnectorMQClient;
|