@onlineapps/mq-client-core 4.0.1 → 4.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.
- package/CHANGELOG.md +220 -0
- package/README.md +174 -0
- package/package.json +1 -1
- package/src/config/queueConfig.js +272 -21
- package/src/config/recurrencesSchema.js +121 -0
- package/src/index.js +47 -0
- package/src/monitoring-initiated.js +187 -0
- package/src/scheduler-request.js +481 -0
- package/src/transports/rabbitmqClient.js +71 -5
|
@@ -1416,6 +1416,70 @@ class RabbitMQClient extends EventEmitter {
|
|
|
1416
1416
|
}
|
|
1417
1417
|
}
|
|
1418
1418
|
|
|
1419
|
+
/**
|
|
1420
|
+
* Race an `amqp.connect()` handshake against its `connectTimeout`, and own the
|
|
1421
|
+
* handshake the timeout abandons.
|
|
1422
|
+
*
|
|
1423
|
+
* When the timeout wins, the race rejects but the handshake does not stop: it
|
|
1424
|
+
* can still complete into a full AMQP connection that no field of this client
|
|
1425
|
+
* points at, so `disconnect()` never closes it and it keeps the process alive
|
|
1426
|
+
* (INFRA 359, measured with a proxy delaying the handshake past the timeout).
|
|
1427
|
+
* The rejection the caller receives is unchanged; what changes is that the
|
|
1428
|
+
* abandoned handshake is closed the moment it completes.
|
|
1429
|
+
*
|
|
1430
|
+
* @private
|
|
1431
|
+
* @param {Promise<Object>} connectPromise - the handshake from `amqp.connect()`
|
|
1432
|
+
* @param {Promise<never>} timeoutPromise - rejects with the timeout error
|
|
1433
|
+
* @param {string} phase - 'connect' or 'reconnect', named in the log lines
|
|
1434
|
+
* @returns {Promise<Object>} the connection, when the handshake won the race
|
|
1435
|
+
*/
|
|
1436
|
+
async _raceHandshake(connectPromise, timeoutPromise, phase) {
|
|
1437
|
+
let abandoned = false;
|
|
1438
|
+
const timeoutLeg = timeoutPromise.catch((err) => {
|
|
1439
|
+
abandoned = true;
|
|
1440
|
+
throw err;
|
|
1441
|
+
});
|
|
1442
|
+
try {
|
|
1443
|
+
return await Promise.race([connectPromise, timeoutLeg]);
|
|
1444
|
+
} catch (err) {
|
|
1445
|
+
if (abandoned) {
|
|
1446
|
+
this._closeAbandonedHandshake(connectPromise, phase);
|
|
1447
|
+
}
|
|
1448
|
+
throw err;
|
|
1449
|
+
}
|
|
1450
|
+
}
|
|
1451
|
+
|
|
1452
|
+
/**
|
|
1453
|
+
* Close the connection an abandoned handshake produces, whenever it completes.
|
|
1454
|
+
* A handshake that fails after its timeout opened nothing; its error adds
|
|
1455
|
+
* nothing to the timeout the caller already received.
|
|
1456
|
+
* @private
|
|
1457
|
+
* @param {Promise<Object>} connectPromise - the handshake the timeout abandoned
|
|
1458
|
+
* @param {string} phase - 'connect' or 'reconnect'
|
|
1459
|
+
*/
|
|
1460
|
+
_closeAbandonedHandshake(connectPromise, phase) {
|
|
1461
|
+
connectPromise.then(
|
|
1462
|
+
async (late) => {
|
|
1463
|
+
this._logger.warn(
|
|
1464
|
+
`[RabbitMQClient] Handshake completed after the ${phase} timeout (${this._connectTimeout} ms) - `
|
|
1465
|
+
+ 'closing that connection, nothing in this client owns it'
|
|
1466
|
+
);
|
|
1467
|
+
try {
|
|
1468
|
+
await late.close();
|
|
1469
|
+
} catch (closeErr) {
|
|
1470
|
+
this._logger.warn(
|
|
1471
|
+
`[RabbitMQClient] Error closing the connection whose handshake outlived the ${phase} timeout: ${closeErr.message}`
|
|
1472
|
+
);
|
|
1473
|
+
}
|
|
1474
|
+
},
|
|
1475
|
+
(lateErr) => {
|
|
1476
|
+
this._logger.debug(
|
|
1477
|
+
`[RabbitMQClient] Handshake abandoned by the ${phase} timeout failed afterwards: ${lateErr.message}`
|
|
1478
|
+
);
|
|
1479
|
+
}
|
|
1480
|
+
);
|
|
1481
|
+
}
|
|
1482
|
+
|
|
1419
1483
|
/**
|
|
1420
1484
|
* Clear all active timers
|
|
1421
1485
|
* @private
|
|
@@ -1459,7 +1523,7 @@ class RabbitMQClient extends EventEmitter {
|
|
|
1459
1523
|
}
|
|
1460
1524
|
});
|
|
1461
1525
|
this._logger.debug('[RabbitMQClient] Starting connection race...');
|
|
1462
|
-
this._connection = await
|
|
1526
|
+
this._connection = await this._raceHandshake(connectPromise, timeoutPromise, 'connect');
|
|
1463
1527
|
if (connectTimeoutTimer) {
|
|
1464
1528
|
this._clearTimeout(connectTimeoutTimer);
|
|
1465
1529
|
connectTimeoutTimer = null;
|
|
@@ -3437,9 +3501,11 @@ class RabbitMQClient extends EventEmitter {
|
|
|
3437
3501
|
// leaves exactly those without a route of their own, because a dead-letter
|
|
3438
3502
|
// route on a dead-letter queue is a loop or a chain with no end
|
|
3439
3503
|
// (`mq-consumer-contract` 002 point 2, 003 point 2). Until d.452 the gate
|
|
3440
|
-
// asked only the first question, so the operator's own queue
|
|
3441
|
-
//
|
|
3442
|
-
//
|
|
3504
|
+
// asked only the first question, so the operator's own queue could not be
|
|
3505
|
+
// consumed through this library at all. Who reads such a queue is that
|
|
3506
|
+
// service's own fact, not this file's —
|
|
3507
|
+
// @see api/infra/api_monitoring/src/consumer/deadLetterPeek.js
|
|
3508
|
+
// The second question is derived from the templates
|
|
3443
3509
|
// (`queueConfig.isDeadLetterTarget()`), never from a list of names, so it
|
|
3444
3510
|
// cannot fall behind them; every other queue with no route is refused
|
|
3445
3511
|
// exactly as before, with the same sentence.
|
|
@@ -3939,7 +4005,7 @@ class RabbitMQClient extends EventEmitter {
|
|
|
3939
4005
|
)), this._connectTimeout);
|
|
3940
4006
|
});
|
|
3941
4007
|
|
|
3942
|
-
const revived = await
|
|
4008
|
+
const revived = await this._raceHandshake(connectPromise, timeoutPromise, 'reconnect');
|
|
3943
4009
|
|
|
3944
4010
|
// The caller may have disposed of this client while that handshake was
|
|
3945
4011
|
// in flight. The socket is up, and it belongs to nobody: keeping it
|