mirror of
https://github.com/jambonz/sbc-outbound.git
synced 2025-12-19 04:27:45 +00:00
refined the method for syncing call count updates and added debugging (#163)
* refined the method for syncing call count updates and added debugging * wip * include callId in debug key
This commit is contained in:
2
app.js
2
app.js
@@ -69,6 +69,7 @@ const {
|
|||||||
retrieveSet,
|
retrieveSet,
|
||||||
isMemberOfSet,
|
isMemberOfSet,
|
||||||
addKey,
|
addKey,
|
||||||
|
deleteKey,
|
||||||
retrieveKey
|
retrieveKey
|
||||||
} = require('@jambonz/realtimedb-helpers')({}, logger);
|
} = require('@jambonz/realtimedb-helpers')({}, logger);
|
||||||
|
|
||||||
@@ -104,6 +105,7 @@ srf.locals = {...srf.locals,
|
|||||||
realtimeDbHelpers: {
|
realtimeDbHelpers: {
|
||||||
client: redisClient,
|
client: redisClient,
|
||||||
addKey,
|
addKey,
|
||||||
|
deleteKey,
|
||||||
retrieveKey,
|
retrieveKey,
|
||||||
createHash,
|
createHash,
|
||||||
retrieveHash,
|
retrieveHash,
|
||||||
|
|||||||
@@ -618,7 +618,17 @@ class CallSession extends Emitter {
|
|||||||
const abandoned = err.message && err.message.includes('rtpengine failed: Unknown call-id');
|
const abandoned = err.message && err.message.includes('rtpengine failed: Unknown call-id');
|
||||||
const status = err.status || (abandoned ? 487 : 500);
|
const status = err.status || (abandoned ? 487 : 500);
|
||||||
if (err instanceof SipError) this.logger.info(`final call failure ${status}`);
|
if (err instanceof SipError) this.logger.info(`final call failure ${status}`);
|
||||||
else if (!abandoned) this.logger.error(err, 'unexpected call failure');
|
else if (!abandoned) {
|
||||||
|
const {writeCallCount, writeCallCountSP, writeCallCountApp} = this.req.srf.locals;
|
||||||
|
this.logger.error({err}, 'unexpected call failure');
|
||||||
|
nudgeCallCounts(this.req, 'failure', {
|
||||||
|
service_provider_sid: this.service_provider_sid,
|
||||||
|
account_sid: this.account_sid,
|
||||||
|
application_sid: this.application_sid,
|
||||||
|
callId: this.req.locals.callId
|
||||||
|
}, this.decrKey, {writeCallCountSP, writeCallCount, writeCallCountApp})
|
||||||
|
.catch((err) => this.logger.error(err, 'Error decrementing call counts'));
|
||||||
|
}
|
||||||
debug(`got final outdial error: ${err}`);
|
debug(`got final outdial error: ${err}`);
|
||||||
if (!passFailure) this.res.send(status);
|
if (!passFailure) this.res.send(status);
|
||||||
this.emit('failed');
|
this.emit('failed');
|
||||||
@@ -643,7 +653,7 @@ class CallSession extends Emitter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
if ('abandonded' !== err.message) this.logger.error(err, `Error setting up outbound call to: ${uris}`);
|
if ('abandonded' !== err.message) this.logger.error({err}, `Error setting up outbound call to: ${uris}`);
|
||||||
this.emit('failed');
|
this.emit('failed');
|
||||||
this.srf.endSession(this.req);
|
this.srf.endSession(this.req);
|
||||||
this.rtpEngineResource.destroy();
|
this.rtpEngineResource.destroy();
|
||||||
@@ -694,16 +704,14 @@ class CallSession extends Emitter {
|
|||||||
|
|
||||||
if (process.env.JAMBONES_HOSTING || trackingOn) {
|
if (process.env.JAMBONES_HOSTING || trackingOn) {
|
||||||
const {writeCallCount, writeCallCountSP, writeCallCountApp} = this.req.srf.locals;
|
const {writeCallCount, writeCallCountSP, writeCallCountApp} = this.req.srf.locals;
|
||||||
if (!this.req.locals.callCountNudged) {
|
this.logger.debug('decrementing call count at end of call');
|
||||||
this.req.locals.callCountNudged = true;
|
await nudgeCallCounts(this.req, 'complete', {
|
||||||
this.logger.debug('decrementing call count at end of call');
|
service_provider_sid: this.service_provider_sid,
|
||||||
await nudgeCallCounts(this.logger, {
|
account_sid: this.account_sid,
|
||||||
service_provider_sid: this.service_provider_sid,
|
application_sid: this.application_sid,
|
||||||
account_sid: this.account_sid,
|
callId: this.req.locals.callId
|
||||||
application_sid: this.application_sid
|
}, this.decrKey, {writeCallCountSP, writeCallCount, writeCallCountApp})
|
||||||
}, this.decrKey, {writeCallCountSP, writeCallCount, writeCallCountApp})
|
.catch((err) => this.logger.error(err, 'Error decrementing call counts'));
|
||||||
.catch((err) => this.logger.error(err, 'Error decrementing call counts'));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* write cdr for connected call */
|
/* write cdr for connected call */
|
||||||
|
|||||||
@@ -17,6 +17,8 @@ module.exports = (srf, logger, redisClient) => {
|
|||||||
const initLocals = async(req, res, next) => {
|
const initLocals = async(req, res, next) => {
|
||||||
req.locals = req.locals || {};
|
req.locals = req.locals || {};
|
||||||
const callId = req.get('Call-ID');
|
const callId = req.get('Call-ID');
|
||||||
|
req.locals.nudge = 0;
|
||||||
|
req.locals.callId = callId;
|
||||||
req.locals.account_sid = req.get('X-Account-Sid');
|
req.locals.account_sid = req.get('X-Account-Sid');
|
||||||
req.locals.application_sid = req.get('X-Application-Sid');
|
req.locals.application_sid = req.get('X-Application-Sid');
|
||||||
req.locals.record_all_calls = req.get('X-Record-All-Calls');
|
req.locals.record_all_calls = req.get('X-Record-All-Calls');
|
||||||
@@ -106,13 +108,12 @@ module.exports = (srf, logger, redisClient) => {
|
|||||||
try {
|
try {
|
||||||
/* decrement count if INVITE is later rejected */
|
/* decrement count if INVITE is later rejected */
|
||||||
res.once('end', async({status}) => {
|
res.once('end', async({status}) => {
|
||||||
if (status > 200 && !req.locals.callCountNudged) {
|
if (status > 200) {
|
||||||
req.locals.callCountNudged = true;
|
nudgeCallCounts(req, 'failure', {
|
||||||
logger.debug('decrementing call count due to call rejection');
|
|
||||||
nudgeCallCounts(logger, {
|
|
||||||
service_provider_sid,
|
service_provider_sid,
|
||||||
account_sid,
|
account_sid,
|
||||||
application_sid
|
application_sid,
|
||||||
|
callId: req.locals.callId
|
||||||
}, decrKey, {writeCallCountSP, writeCallCount, writeCallCountApp})
|
}, decrKey, {writeCallCountSP, writeCallCount, writeCallCountApp})
|
||||||
.catch((err) => logger.error(err, 'Error decrementing call counts'));
|
.catch((err) => logger.error(err, 'Error decrementing call counts'));
|
||||||
const tags = ['accepted:no', `sipStatus:${status}`];
|
const tags = ['accepted:no', `sipStatus:${status}`];
|
||||||
@@ -125,10 +126,11 @@ module.exports = (srf, logger, redisClient) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
/* increment the call count */
|
/* increment the call count */
|
||||||
const {callsSP, calls} = await nudgeCallCounts(logger, {
|
const {callsSP, calls} = await nudgeCallCounts(req, 'init', {
|
||||||
service_provider_sid,
|
service_provider_sid,
|
||||||
account_sid,
|
account_sid,
|
||||||
application_sid
|
application_sid,
|
||||||
|
callId: req.locals.callId
|
||||||
}, incrKey, {writeCallCountSP, writeCallCount, writeCallCountApp});
|
}, incrKey, {writeCallCountSP, writeCallCount, writeCallCountApp});
|
||||||
|
|
||||||
/* compare to account's limit, though avoid db hit when call count is low */
|
/* compare to account's limit, though avoid db hit when call count is low */
|
||||||
|
|||||||
89
lib/utils.js
89
lib/utils.js
@@ -131,13 +131,96 @@ const createHealthCheckApp = (port, logger) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const nudgeCallCounts = async(logger, sids, nudgeOperator, writers) => {
|
/**
|
||||||
const {service_provider_sid, account_sid, application_sid} = sids;
|
* nudgeCallCounts - increment or decrement call counts in redis
|
||||||
|
*
|
||||||
|
* current nudge value
|
||||||
|
* -----------------------------------------
|
||||||
|
* why | -1 | 0 | 1 |
|
||||||
|
* -----------------------------------------
|
||||||
|
* init | no-op | +1 | N/A |
|
||||||
|
* failure | N/A | -1 | -1 |
|
||||||
|
* complete| N/A | N/A | -1 |
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
const shouldNudge = (why, req) => {
|
||||||
|
const {nudge, logger} = req.locals;
|
||||||
|
let modifyCount = false;
|
||||||
|
const originalNudge = nudge;
|
||||||
|
|
||||||
|
switch (why) {
|
||||||
|
case 'init':
|
||||||
|
if (nudge === 0) {
|
||||||
|
// normal case: new call, increment call count
|
||||||
|
req.locals.nudge = 1;
|
||||||
|
modifyCount = true;
|
||||||
|
}
|
||||||
|
else if (nudge === -1) {
|
||||||
|
// extremely quick cancel, don't increment call count
|
||||||
|
req.locals.nudge = 0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
logger.info(`shouldNudge: unexpected nudge value ${nudge} for ${why}`);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'failure':
|
||||||
|
if (nudge === 1) {
|
||||||
|
// normal case of call failed for any reason, decrement call count
|
||||||
|
req.locals.nudge = 0;
|
||||||
|
modifyCount = true;
|
||||||
|
}
|
||||||
|
else if (nudge === 0) {
|
||||||
|
// very quick failure dont decrement call count
|
||||||
|
req.locals.nudge = -1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
logger.info(`shouldNudge: unexpected nudge value ${nudge} for ${why}`);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'complete':
|
||||||
|
if (nudge === 1) {
|
||||||
|
// normal case of call completed, decrement call count
|
||||||
|
req.locals.nudge = 0;
|
||||||
|
modifyCount = true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
logger.info(`shouldNudge: unexpected nudge value ${nudge} for ${why}`);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
logger.info(`shouldNudge: unexpected why value ${why}`);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.info(`shouldNudge: '${why}': updating count: ${modifyCount}, nudge: ${originalNudge} -> ${req.locals.nudge}`);
|
||||||
|
return modifyCount;
|
||||||
|
};
|
||||||
|
|
||||||
|
const nudgeCallCounts = async(req, why, sids, nudgeOperator, writers) => {
|
||||||
|
const {logger} = req.locals;
|
||||||
|
const {service_provider_sid, account_sid, application_sid, callId} = sids;
|
||||||
const {writeCallCount, writeCallCountSP, writeCallCountApp} = writers;
|
const {writeCallCount, writeCallCountSP, writeCallCountApp} = writers;
|
||||||
const nudges = [];
|
const nudges = [];
|
||||||
const writes = [];
|
const writes = [];
|
||||||
|
|
||||||
logger.debug(sids, 'nudgeCallCounts');
|
if (!shouldNudge(why, req)) {
|
||||||
|
return {callsSP: null, calls: null, callsApp: null};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (process.env.JAMBONES_DEBUG_CALL_COUNTS) {
|
||||||
|
const {srf} = require('..');
|
||||||
|
const {addKey, deleteKey} = srf.locals.realtimeDbHelpers;
|
||||||
|
|
||||||
|
if (why === 'init') {
|
||||||
|
// save for 3 days
|
||||||
|
await addKey(`debug:outcalls:${account_sid}:${callId}`, new Date().toISOString(), 259200);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
await deleteKey(`debug:outcalls:${account_sid}:${callId}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (process.env.JAMBONES_TRACK_SP_CALLS) {
|
if (process.env.JAMBONES_TRACK_SP_CALLS) {
|
||||||
const key = makeSPCallCountKey(service_provider_sid);
|
const key = makeSPCallCountKey(service_provider_sid);
|
||||||
|
|||||||
Reference in New Issue
Block a user