* fix: keep siprec recording alive across a feature server transfer
A cross-feature-server move (enqueue/dequeue or conference) re-negotiates the
feature-server leg in _onFeatureServerTransfer, but nothing rebuilt the rtpengine
subscription the SIPREC recording forks from, so the recorder went silent from the
moment the call moved. The fresh destroy handler installed on the new leg also
dropped the _stopRecording() call the original handlers have, so the SIPREC dialog
was never BYEd and the recorder had to wait out its media timeout.
Rebuild the subscription after the transfer re-negotiates media, and stop the
recording when the transferred leg ends. The resubscribe call is guarded so this
is safe to deploy before @jambonz/siprec-client-utils is bumped.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: drop the siprec re-subscribe, keep the missing teardown
Running the cross-feature-server move against a real two-feature-server cluster
showed the rtpengine subscription survives the REFER on its own: with
resubscribe() removed, the fork still carried the post-transfer conversation
(50 packets/s on both streams, and the words spoken after the move transcribed
straight out of the recording). rtpengine keeps non-offer-answer subscriptions
across an answer, so there was never anything to rebuild - the earlier commit
was fixing a fault that does not exist.
What does fail, and what this branch still fixes, is the teardown: the destroy
handler installed on the transferred leg never stopped the recording, so the
recorder was left without a BYE.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Scale-in completion never happened: app.js holds the placeholder
Emitter that autoscale-manager returns synchronously (the real
SnsNotifier replaces it later inside an async IIFE), so the completion
poller never saw operationalState change; it also called the
nonexistent scaleIn() rather than completeScaleIn(). Instances in
Terminating:Wait therefore always burned the full lifecycle hook
heartbeat timeout.
In addition, nothing consumed dryUpCalls: a draining SBC kept accepting
new INVITEs sent directly to its public address right up until
termination.
Changes:
- complete the scale-in from within the ScaleIn handler in
autoscale-manager, where the real notifier is in scope
- while draining, reject new INVITEs with 503 so senders fail over to
another SBC (INVITE with Replaces is allowed through since it targets
a call already in progress here)
- a server may run several sbc-inbound and sbc-outbound processes, and
completing the hook when only this process is idle would terminate
the instance while sibling processes still have calls; each process
now reports its call count to redis (lib/call-count-reporter.js, with
a companion change in sbc-outbound) and the draining process
completes only when the server-wide count is zero on two consecutive
checks, falling back to its own count if no reports are present
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
The error handler was using (req, res, next, err) but drachtio-srf
error middleware expects (err, req, res, next). This caused
"res.send is not a function" errors when the handler was invoked.
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* Add STRAIGHT_JOIN to CIDR gateway query to prevent MySQL optimizer from choosing inefficient full table scan on voip_carriers table.
* update tests with latest schema
* fix test data
* security issues
* update workflow actions
* allow uas leg can send re-invite with outbound gatway credential
* fix cannot get register username/password
* fix cannot get register username/password
* fix cannot get register username/password
* fixed failing test cases
* support incoming calls from registration trunks with ephemeral gateways
* fix bug with multiple ephemeral gateways
* update to pino 10.1.0
* update eslint
* Fixed issue when wild cards or regex is used in phone number for multiple carriers
https://github.com/jambonz/sbc-inbound/issues/201
* Implemanted the regex/pattern based logic when url is a sip_realm
* Refactored getApplicationForDidAndCarrier as it is failing to parse other regex if first regex is invalid
In gateway is defined at "all accounts" using the phone number's account_sid
* Performance improvements
* Exported getApplicationForDidAndCarriers method
* Added additional unit test cases