From 6f9c6293799236f9c97e18673ae2178e7e6b8a9e Mon Sep 17 00:00:00 2001 From: Dave Horton Date: Mon, 9 Feb 2026 10:32:57 -0500 Subject: [PATCH] add configurable backup for outbound reg failure (#128) --- lib/config.js | 4 ++- lib/regbot.js | 8 ++++-- lib/sip-trunk-register.js | 26 ++++++++++------- package-lock.json | 60 ++++++++++++++++++++++++++------------- package.json | 2 +- 5 files changed, 65 insertions(+), 35 deletions(-) diff --git a/lib/config.js b/lib/config.js index b60fa07..5fb1f05 100644 --- a/lib/config.js +++ b/lib/config.js @@ -42,6 +42,7 @@ const JAMBONES_REGBOT_BATCH_SIZE = process.env.JAMBONES_REGBOT_BATCH_SIZE || 10; const OPTIONS_RESPONSE_REMOVE = process.env.OPTIONS_RESPONSE_REMOVE?.split(',').map(Number) || []; const REGISTER_RESPONSE_REMOVE = process.env.REGISTER_RESPONSE_REMOVE?.split(',').map(Number) || []; const JAMBONES_REGBOT_USER_AGENT = process.env.JAMBONES_REGBOT_USER_AGENT ; +const JAMBONES_REGBOT_FAILURE_RETRY_INTERVAL = process.env.JAMBONES_REGBOT_FAILURE_RETRY_INTERVAL; module.exports = { JAMBONES_MYSQL_HOST, @@ -77,5 +78,6 @@ module.exports = { JAMBONES_REGBOT_BATCH_SIZE, OPTIONS_RESPONSE_REMOVE, REGISTER_RESPONSE_REMOVE, - JAMBONES_REGBOT_USER_AGENT + JAMBONES_REGBOT_USER_AGENT, + JAMBONES_REGBOT_FAILURE_RETRY_INTERVAL }; diff --git a/lib/regbot.js b/lib/regbot.js index ea5a536..48cefb5 100644 --- a/lib/regbot.js +++ b/lib/regbot.js @@ -4,11 +4,13 @@ const { JAMBONES_REGBOT_MIN_EXPIRES_INTERVAL, JAMBONES_REGBOT_CONTACT_USE_IP, REGISTER_RESPONSE_REMOVE, - JAMBONES_REGBOT_USER_AGENT + JAMBONES_REGBOT_USER_AGENT, + JAMBONES_REGBOT_FAILURE_RETRY_INTERVAL } = require('./config'); const {isValidDomainOrIP, isValidIPv4} = require('./utils'); const DEFAULT_EXPIRES = (parseInt(JAMBONES_REGBOT_DEFAULT_EXPIRES_INTERVAL) || 3600); const MIN_EXPIRES = (parseInt(JAMBONES_REGBOT_MIN_EXPIRES_INTERVAL) || 30); +const FAILURE_RETRY_INTERVAL = (parseInt(JAMBONES_REGBOT_FAILURE_RETRY_INTERVAL) || 300); const assert = require('assert'); const version = require('../package.json').version; const useragent = JAMBONES_REGBOT_USER_AGENT || `Jambonz ${version}`; @@ -143,7 +145,7 @@ class Regbot { if (res.status !== 200) { this.status = 'fail'; this.logger.info(`${this.aor}: got ${res.status} registering to ${this.ipv4}:${this.port}`); - this.timer = setTimeout(this.register.bind(this, srf), 30 * 1000); + this.timer = setTimeout(this.register.bind(this, srf), FAILURE_RETRY_INTERVAL * 1000); if (REGISTER_RESPONSE_REMOVE.includes(res.status)) { const { updateCarrierBySid, lookupCarrierBySid } = srf.locals.dbHelpers; await updateCarrierBySid(this.voip_carrier_sid, {requires_register: false}); @@ -245,7 +247,7 @@ class Regbot { }); } catch (err) { this.logger.error({ err }, `${this.aor}: Error registering to ${this.ipv4}:${this.port}`); - this.timer = setTimeout(this.register.bind(this, srf), 60 * 1000); + this.timer = setTimeout(this.register.bind(this, srf), FAILURE_RETRY_INTERVAL * 1000); updateVoipCarriersRegisterStatus(this.voip_carrier_sid, JSON.stringify({ status: 'fail', reason: err diff --git a/lib/sip-trunk-register.js b/lib/sip-trunk-register.js index cadadff..8358b6d 100644 --- a/lib/sip-trunk-register.js +++ b/lib/sip-trunk-register.js @@ -63,24 +63,30 @@ async function getLocalSIPDomain(logger, srf) { */ function getUniqueGateways(gateways, logger) { const uniqueGatewayKeys = new Set(); + const duplicateCounts = new Map(); + const uniqueGateways = []; - return gateways.filter((gw) => { + for (const gw of gateways) { const key = `${gw.ipv4}:${gw.sip_realm}:${gw.carrier?.register_username}:${gw.carrier?.register_password}`; if (!gw.carrier?.register_password) { logger.info({gw}, `Gateway ${key} does not have a password, ignoring`); - return false; + continue; } - // If we've already seen this key, it's a duplicate if (uniqueGatewayKeys.has(key)) { - logger.info({gw}, `Found duplicate gateway ${key}, ignoring`); - return false; + duplicateCounts.set(key, (duplicateCounts.get(key) || 1) + 1); + } else { + uniqueGatewayKeys.add(key); + uniqueGateways.push(gw); } + } - // Otherwise, add it to our Set and keep this gateway - uniqueGatewayKeys.add(key); - return true; - }); + // Log summary for each duplicate gateway + for (const [key, count] of duplicateCounts) { + logger.info({key, count}, `Found ${count} duplicate gateways for ${key}, ignoring duplicates`); + } + + return uniqueGateways; } module.exports = async(logger, srf) => { @@ -222,7 +228,7 @@ const updateCarrierRegbots = async(logger, srf) => { if (hasChanged) { debug('updateCarrierRegbots: got new or changed carriers'); - logger.info({gws}, 'updateCarrierRegbots: got new or changed carriers'); + logger.info({count: gws.length}, 'updateCarrierRegbots: got new or changed carriers'); // Clear and repopulate arrays in chunks to avoid argument limit carriers.length = 0; diff --git a/package-lock.json b/package-lock.json index d7c0d90..e0782d6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19,7 +19,7 @@ "debug": "^4.4.3", "drachtio-mw-registration-parser": "^0.1.2", "drachtio-mw-response-time": "^1.0.2", - "drachtio-srf": "^5.0.5", + "drachtio-srf": "^5.0.18", "pino": "^10.1.0", "short-uuid": "^4.2.2" }, @@ -1366,9 +1366,10 @@ } }, "node_modules/delegates": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/delegates/-/delegates-0.1.0.tgz", - "integrity": "sha512-tPYr58xmVlUWcL8zPk6ZAxP6XqiYx5IIn395dkeER12JmMy8P6ipGKnUvgD++g8+uCaALfs/CRERixvKBu1pow==" + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==", + "license": "MIT" }, "node_modules/denque": { "version": "2.1.0", @@ -1405,32 +1406,50 @@ "integrity": "sha512-d+DtKuqhpkSBBkRfwcgS3x26T3lrdgo86yVWZ4wy+K8RtS1faT3hgLBq9EPEYSDkcw76r4klvdDWPhTrPqGAQw==" }, "node_modules/drachtio-srf": { - "version": "5.0.13", - "resolved": "https://registry.npmjs.org/drachtio-srf/-/drachtio-srf-5.0.13.tgz", - "integrity": "sha512-IG62MLLzhXjQtbjX6T6I8jXK6QhWQwsblkO3+F2Zhcu4lXBO3W12rrKyAPsw6GimRSSXIkvMbn5/je8AU/xehQ==", + "version": "5.0.18", + "resolved": "https://registry.npmjs.org/drachtio-srf/-/drachtio-srf-5.0.18.tgz", + "integrity": "sha512-gm8kc+w0FuWozR6oprcMqa2oPf9dpMABOrbUZle9XcsvJ+DZxpOk11gBBmtj12oSjPgb5hIi+jxzmI6blKVDRw==", "license": "MIT", "dependencies": { - "debug": "^3.2.7", - "delegates": "^0.1.0", - "node-noop": "^0.0.1", + "debug": "^4.4.3", + "delegates": "^1.0.0", + "node-noop": "^1.0.0", "only": "^0.0.2", "sdp-transform": "^2.15.0", - "short-uuid": "^4.2.2", + "short-uuid": "^5.2.0", "sip-methods": "^0.3.0", "sip-status": "^0.1.0", - "utils-merge": "^1.0.0", + "utils-merge": "^1.0.1", "uuid-random": "^1.3.2" }, "engines": { "node": ">= 18.x" } }, - "node_modules/drachtio-srf/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "node_modules/drachtio-srf/node_modules/short-uuid": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/short-uuid/-/short-uuid-5.2.0.tgz", + "integrity": "sha512-296/Nzi4DmANh93iYBwT4NoYRJuHnKEzefrkSagQbTH/A6NTaB68hSPDjm5IlbI5dx9FXdmtqPcj6N5H+CPm6w==", + "license": "MIT", "dependencies": { - "ms": "^2.1.1" + "any-base": "^1.1.0", + "uuid": "^9.0.1" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/drachtio-srf/node_modules/uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" } }, "node_modules/dunder-proto": { @@ -3313,9 +3332,10 @@ "dev": true }, "node_modules/node-noop": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/node-noop/-/node-noop-0.0.1.tgz", - "integrity": "sha512-kAUvIRxZyDYFTLqGj+7zqXduG89vtqGmNMt9qDMvYH3H8uNTCOTz5ZN1q2Yg8++fWbzv+ERtYVqaOH42Ag5OpA==" + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-noop/-/node-noop-1.0.0.tgz", + "integrity": "sha512-1lpWqKwZ9yUosQfW1uy3jm6St4ZbmeDKKGmdzwzedbyBI4LgHtGyL1ofDdqiSomgaYaSERi+qWtj64huJQjl7g==", + "license": "BSD-2-Clause" }, "node_modules/node-object-hash": { "version": "2.3.10", diff --git a/package.json b/package.json index 1282e39..f867299 100644 --- a/package.json +++ b/package.json @@ -38,7 +38,7 @@ "debug": "^4.4.3", "drachtio-mw-registration-parser": "^0.1.2", "drachtio-mw-response-time": "^1.0.2", - "drachtio-srf": "^5.0.5", + "drachtio-srf": "^5.0.18", "pino": "^10.1.0", "short-uuid": "^4.2.2" },