From 7c64dea67e295dba27ede7ce3f4717164401bcb4 Mon Sep 17 00:00:00 2001 From: Rajesh Kumar Date: Wed, 19 Nov 2025 11:46:48 +0530 Subject: [PATCH 1/4] fix(calling): fix the timer issue for call keepalive --- .../calling/src/CallingClient/calling/call.test.ts | 13 +++++++------ packages/calling/src/CallingClient/calling/call.ts | 12 ++++++++---- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/packages/calling/src/CallingClient/calling/call.test.ts b/packages/calling/src/CallingClient/calling/call.test.ts index 30c8b760160..5f54c9b698d 100644 --- a/packages/calling/src/CallingClient/calling/call.test.ts +++ b/packages/calling/src/CallingClient/calling/call.test.ts @@ -948,7 +948,7 @@ describe('State Machine handler tests', () => { call['callStateMachine'].state.value = 'S_SEND_CALL_CONNECT'; webex.request.mockReturnValue(statusPayload); - jest.spyOn(global, 'setInterval'); + jest.spyOn(global, 'setTimeout'); const funcSpy = jest.spyOn(call, 'postStatus').mockResolvedValue(statusPayload); const logSpy = jest.spyOn(log, 'info'); @@ -962,7 +962,8 @@ describe('State Machine handler tests', () => { */ await flushPromises(3); - expect(setInterval).toHaveBeenCalledTimes(1); + expect(setTimeout).toHaveBeenCalledTimes(2); + expect(setTimeout).toHaveBeenLastCalledWith(expect.any(Function), DEFAULT_SESSION_TIMER); expect(funcSpy).toBeCalledTimes(1); expect(logSpy).toBeCalledWith('Session refresh successful', { file: 'call', @@ -984,7 +985,7 @@ describe('State Machine handler tests', () => { }); webex.request.mockReturnValue(statusPayload); - jest.spyOn(global, 'clearInterval'); + jest.spyOn(global, 'clearTimeout'); const emitSpy = jest.spyOn(call, 'emit'); @@ -1000,7 +1001,7 @@ describe('State Machine handler tests', () => { await Promise.resolve(); await Promise.resolve(); - expect(clearInterval).toHaveBeenCalledTimes(1); + expect(clearTimeout).toHaveBeenCalledTimes(1); expect(funcSpy).toBeCalledTimes(1); expect(emitSpy).toHaveBeenCalledWith(CALL_EVENT_KEYS.DISCONNECT, call.getCorrelationId()); }); @@ -1012,7 +1013,7 @@ describe('State Machine handler tests', () => { }); webex.request.mockReturnValue(statusPayload); - jest.spyOn(global, 'clearInterval'); + jest.spyOn(global, 'clearTimeout'); call.on(CALL_EVENT_KEYS.CALL_ERROR, (errObj) => { expect(errObj.type).toStrictEqual(ERROR_TYPE.FORBIDDEN_ERROR); @@ -1039,7 +1040,7 @@ describe('State Machine handler tests', () => { await Promise.resolve(); await Promise.resolve(); - expect(clearInterval).toHaveBeenCalledTimes(2); // check this + expect(clearTimeout).toHaveBeenCalledTimes(2); expect(funcSpy).toBeCalledTimes(1); }); diff --git a/packages/calling/src/CallingClient/calling/call.ts b/packages/calling/src/CallingClient/calling/call.ts index 3fdfec0c92f..26aeab98b30 100644 --- a/packages/calling/src/CallingClient/calling/call.ts +++ b/packages/calling/src/CallingClient/calling/call.ts @@ -1524,15 +1524,19 @@ export class Call extends Eventing implements ICall { if (this.sessionTimer) { log.log('Resetting session timer', loggerContext); - clearInterval(this.sessionTimer); + clearTimeout(this.sessionTimer); } - this.sessionTimer = setInterval(async () => { + this.sessionTimer = setTimeout(async () => { try { // eslint-disable-next-line @typescript-eslint/no-unused-vars const res = await this.postStatus(); + + // Starting the interval again with the DEFAULT_SESSION_TIMER + clearTimeout(this.sessionTimer); this.callKeepaliveRetryCount = 0; this.callKeepaliveInterval = undefined; + this.sendCallStateMachineEvt({type: 'E_CALL_ESTABLISHED'}); log.info(`Session refresh successful`, loggerContext); } catch (err: unknown) { @@ -1545,7 +1549,7 @@ export class Call extends Eventing implements ICall { */ /* istanbul ignore next */ if (this.sessionTimer) { - clearInterval(this.sessionTimer); + clearTimeout(this.sessionTimer); } const abort = await handleCallErrors( @@ -1561,7 +1565,7 @@ export class Call extends Eventing implements ICall { // If we have reached the max retry count, do not attempt to refresh the session if (this.callKeepaliveRetryCount === MAX_CALL_KEEPALIVE_RETRY_COUNT) { this.callKeepaliveRetryCount = 0; - clearInterval(this.sessionTimer); + clearTimeout(this.sessionTimer); this.sessionTimer = undefined; this.callKeepaliveInterval = undefined; From 41813ed46720f43b9690f09d51610f398a9a8a8f Mon Sep 17 00:00:00 2001 From: Rajesh Kumar Date: Thu, 20 Nov 2025 15:05:43 +0530 Subject: [PATCH 2/4] fix(calling): update the handleCallEstablished to handle timer --- .../calling/src/CallingClient/calling/call.ts | 134 +++++++++--------- 1 file changed, 69 insertions(+), 65 deletions(-) diff --git a/packages/calling/src/CallingClient/calling/call.ts b/packages/calling/src/CallingClient/calling/call.ts index 26aeab98b30..bd0b7891797 100644 --- a/packages/calling/src/CallingClient/calling/call.ts +++ b/packages/calling/src/CallingClient/calling/call.ts @@ -1527,79 +1527,83 @@ export class Call extends Eventing implements ICall { clearTimeout(this.sessionTimer); } - this.sessionTimer = setTimeout(async () => { - try { - // eslint-disable-next-line @typescript-eslint/no-unused-vars - const res = await this.postStatus(); + const handleTimer = () => { + this.sessionTimer = setTimeout(async () => { + try { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const res = await this.postStatus(); - // Starting the interval again with the DEFAULT_SESSION_TIMER - clearTimeout(this.sessionTimer); - this.callKeepaliveRetryCount = 0; - this.callKeepaliveInterval = undefined; - this.sendCallStateMachineEvt({type: 'E_CALL_ESTABLISHED'}); + // Starting the interval again with the DEFAULT_SESSION_TIMER + clearTimeout(this.sessionTimer); + this.callKeepaliveRetryCount = 0; + this.callKeepaliveInterval = undefined; + handleTimer(); - log.info(`Session refresh successful`, loggerContext); - } catch (err: unknown) { - const error = err; + log.info(`Session refresh successful`, loggerContext); + } catch (err: unknown) { + const error = err; - /* We are clearing the timer here as all are error scenarios. Only scenario where - * timer reset won't be required is 503 with retry after. But that case will - * be handled automatically as Mobius will also reset timer when we post status - * in retry-after scenario. - */ - /* istanbul ignore next */ - if (this.sessionTimer) { - clearTimeout(this.sessionTimer); - } + /* We are clearing the timer here as all are error scenarios. Only scenario where + * timer reset won't be required is 503 with retry after. But that case will + * be handled automatically as Mobius will also reset timer when we post status + * in retry-after scenario. + */ + /* istanbul ignore next */ + if (this.sessionTimer) { + clearTimeout(this.sessionTimer); + } - const abort = await handleCallErrors( - (callError: CallError) => { - this.emit(CALL_EVENT_KEYS.CALL_ERROR, callError); - this.submitCallErrorMetric(callError); - }, - ERROR_LAYER.CALL_CONTROL, - (interval: number) => { - this.callKeepaliveRetryCount += 1; - this.callKeepaliveInterval = interval * 1000; - - // If we have reached the max retry count, do not attempt to refresh the session - if (this.callKeepaliveRetryCount === MAX_CALL_KEEPALIVE_RETRY_COUNT) { - this.callKeepaliveRetryCount = 0; - clearTimeout(this.sessionTimer); - this.sessionTimer = undefined; - this.callKeepaliveInterval = undefined; - - log.warn( - `Max call keepalive retry attempts reached for call: ${this.getCorrelationId()}`, - loggerContext - ); - - return; - } + const abort = await handleCallErrors( + (callError: CallError) => { + this.emit(CALL_EVENT_KEYS.CALL_ERROR, callError); + this.submitCallErrorMetric(callError); + }, + ERROR_LAYER.CALL_CONTROL, + (interval: number) => { + this.callKeepaliveRetryCount += 1; + this.callKeepaliveInterval = interval * 1000; + + // If we have reached the max retry count, do not attempt to refresh the session + if (this.callKeepaliveRetryCount === MAX_CALL_KEEPALIVE_RETRY_COUNT) { + this.callKeepaliveRetryCount = 0; + clearTimeout(this.sessionTimer); + this.sessionTimer = undefined; + this.callKeepaliveInterval = undefined; + + log.warn( + `Max call keepalive retry attempts reached for call: ${this.getCorrelationId()}`, + loggerContext + ); + + return; + } - // Scheduling next keepalive attempt - calling handleCallEstablished - this.sendCallStateMachineEvt({type: 'E_CALL_ESTABLISHED'}); - }, - this.getCorrelationId(), - error, - 'handleCallEstablished', - CALL_FILE - ); + // Scheduling next keepalive attempt - calling handleCallEstablished + this.sendCallStateMachineEvt({type: 'E_CALL_ESTABLISHED'}); + }, + this.getCorrelationId(), + error, + 'handleCallEstablished', + CALL_FILE + ); - if (abort) { - this.sendCallStateMachineEvt({type: 'E_SEND_CALL_DISCONNECT'}); - this.emit(CALL_EVENT_KEYS.DISCONNECT, this.getCorrelationId()); - this.callKeepaliveRetryCount = 0; - this.callKeepaliveInterval = undefined; + if (abort) { + this.sendCallStateMachineEvt({type: 'E_SEND_CALL_DISCONNECT'}); + this.emit(CALL_EVENT_KEYS.DISCONNECT, this.getCorrelationId()); + this.callKeepaliveRetryCount = 0; + this.callKeepaliveInterval = undefined; + } + + await uploadLogs({ + correlationId: this.correlationId, + callId: this.callId, + broadworksCorrelationInfo: this.broadworksCorrelationInfo, + }); } + }, this.callKeepaliveInterval || DEFAULT_SESSION_TIMER); + }; - await uploadLogs({ - correlationId: this.correlationId, - callId: this.callId, - broadworksCorrelationInfo: this.broadworksCorrelationInfo, - }); - } - }, this.callKeepaliveInterval || DEFAULT_SESSION_TIMER); + handleTimer(); } /** From 5407bab4606949c711a9dcf941d2bd57ceb082bd Mon Sep 17 00:00:00 2001 From: Rajesh Kumar Date: Thu, 20 Nov 2025 15:35:31 +0530 Subject: [PATCH 3/4] fix(calling): refactor and simplify the handleCallEstablished --- .../src/CallingClient/calling/call.test.ts | 41 +++-- .../calling/src/CallingClient/calling/call.ts | 162 +++++++++--------- 2 files changed, 108 insertions(+), 95 deletions(-) diff --git a/packages/calling/src/CallingClient/calling/call.test.ts b/packages/calling/src/CallingClient/calling/call.test.ts index 5f54c9b698d..71e0f63d66e 100644 --- a/packages/calling/src/CallingClient/calling/call.test.ts +++ b/packages/calling/src/CallingClient/calling/call.test.ts @@ -948,7 +948,7 @@ describe('State Machine handler tests', () => { call['callStateMachine'].state.value = 'S_SEND_CALL_CONNECT'; webex.request.mockReturnValue(statusPayload); - jest.spyOn(global, 'setTimeout'); + jest.spyOn(global, 'setInterval'); const funcSpy = jest.spyOn(call, 'postStatus').mockResolvedValue(statusPayload); const logSpy = jest.spyOn(log, 'info'); @@ -962,12 +962,12 @@ describe('State Machine handler tests', () => { */ await flushPromises(3); - expect(setTimeout).toHaveBeenCalledTimes(2); - expect(setTimeout).toHaveBeenLastCalledWith(expect.any(Function), DEFAULT_SESSION_TIMER); + expect(setInterval).toHaveBeenCalledTimes(1); + expect(setInterval).toHaveBeenCalledWith(expect.any(Function), DEFAULT_SESSION_TIMER); expect(funcSpy).toBeCalledTimes(1); expect(logSpy).toBeCalledWith('Session refresh successful', { file: 'call', - method: 'handleCallEstablished', + method: 'scheduleCallKeepaliveInterval', }); expect(logSpy).toHaveBeenCalledWith( `${METHOD_START_MESSAGE} with: ${call.getCorrelationId()}`, @@ -985,7 +985,7 @@ describe('State Machine handler tests', () => { }); webex.request.mockReturnValue(statusPayload); - jest.spyOn(global, 'clearTimeout'); + jest.spyOn(global, 'clearInterval'); const emitSpy = jest.spyOn(call, 'emit'); @@ -1001,7 +1001,7 @@ describe('State Machine handler tests', () => { await Promise.resolve(); await Promise.resolve(); - expect(clearTimeout).toHaveBeenCalledTimes(1); + expect(clearInterval).toHaveBeenCalledTimes(1); expect(funcSpy).toBeCalledTimes(1); expect(emitSpy).toHaveBeenCalledWith(CALL_EVENT_KEYS.DISCONNECT, call.getCorrelationId()); }); @@ -1013,7 +1013,7 @@ describe('State Machine handler tests', () => { }); webex.request.mockReturnValue(statusPayload); - jest.spyOn(global, 'clearTimeout'); + jest.spyOn(global, 'clearInterval'); call.on(CALL_EVENT_KEYS.CALL_ERROR, (errObj) => { expect(errObj.type).toStrictEqual(ERROR_TYPE.FORBIDDEN_ERROR); @@ -1040,7 +1040,7 @@ describe('State Machine handler tests', () => { await Promise.resolve(); await Promise.resolve(); - expect(clearTimeout).toHaveBeenCalledTimes(2); + expect(clearInterval).toHaveBeenCalledTimes(1); expect(funcSpy).toBeCalledTimes(1); }); @@ -1054,7 +1054,7 @@ describe('State Machine handler tests', () => { const okPayload = ({statusCode: 200, body: {}}); - const sendEvtSpy = jest.spyOn(call as any, 'sendCallStateMachineEvt'); + const scheduleKeepaliveSpy = jest.spyOn(call as any, 'scheduleCallKeepaliveInterval'); const postStatusSpy = jest .spyOn(call as any, 'postStatus') .mockRejectedValueOnce(errorPayload) @@ -1069,7 +1069,14 @@ describe('State Machine handler tests', () => { await Promise.resolve(); expect(postStatusSpy).toHaveBeenCalledTimes(1); - expect(sendEvtSpy).toHaveBeenCalledWith({type: 'E_CALL_ESTABLISHED'}); + + // Now advance by 1 second for the retry-after interval + jest.advanceTimersByTime(1000); + await Promise.resolve(); + await Promise.resolve(); + + expect(postStatusSpy).toHaveBeenCalledTimes(2); + expect(scheduleKeepaliveSpy).toHaveBeenCalled(); }); it('keepalive ends after reaching max retry count', async () => { @@ -1100,7 +1107,7 @@ describe('State Machine handler tests', () => { jest.advanceTimersByTime(DEFAULT_SESSION_TIMER); await resolvePromise(); - // Now advance by 1 second for each of the 3 more retry attempts (retry-after: 1 second each) + // Now advance by 1 second for each of the 4 retry attempts (retry-after: 1 second each) // Need to do this separately to allow state machine to process and create new intervals jest.advanceTimersByTime(1000); await resolvePromise(); @@ -1111,17 +1118,19 @@ describe('State Machine handler tests', () => { jest.advanceTimersByTime(1000); await resolvePromise(); + jest.advanceTimersByTime(1000); + await resolvePromise(); + // The error handler should detect we're at max retry count and stop expect(warnSpy).toHaveBeenCalledWith( - `Max call keepalive retry attempts reached for call: ${call.getCorrelationId()}`, + `Max keepalive retry attempts reached. Aborting call keepalive for callId: ${call.getCallId()}`, { file: 'call', - method: 'handleCallEstablished', + method: 'keepaliveRetryCallback', } ); - expect(postStatusSpy).toHaveBeenCalledTimes(4); - expect(call['callKeepaliveRetryCount']).toBe(0); - expect(call['sessionTimer']).toBeUndefined(); + expect(postStatusSpy).toHaveBeenCalledTimes(5); + expect(call['callKeepaliveRetryCount']).toBe(4); }); it('state changes during successful incoming call', async () => { diff --git a/packages/calling/src/CallingClient/calling/call.ts b/packages/calling/src/CallingClient/calling/call.ts index bd0b7891797..5b0ded1ad5d 100644 --- a/packages/calling/src/CallingClient/calling/call.ts +++ b/packages/calling/src/CallingClient/calling/call.ts @@ -172,8 +172,6 @@ export class Call extends Eventing implements ICall { private callKeepaliveRetryCount = 0; - private callKeepaliveInterval?: number; - /** * Getter to check if the call is muted or not. * @@ -1499,6 +1497,88 @@ export class Call extends Eventing implements ICall { this.sendCallStateMachineEvt({type: 'E_CALL_CLEARED'}); } + private callKeepaliveRetryCallback = (interval: number) => { + if (this.callKeepaliveRetryCount === MAX_CALL_KEEPALIVE_RETRY_COUNT) { + log.warn( + `Max keepalive retry attempts reached. Aborting call keepalive for callId: ${this.callId}`, + { + file: CALL_FILE, + method: 'keepaliveRetryCallback', + } + ); + + return; + } + + this.callKeepaliveRetryCount += 1; + + setTimeout(async () => { + try { + await this.postStatus(); + this.scheduleCallKeepaliveInterval(); + } catch (err: unknown) { + await this.handleCallKeepaliveError(err); + } + }, interval * 1000); + }; + + private handleCallKeepaliveError = async (err: unknown) => { + const error = err; + + /* We are clearing the timer here as all are error scenarios. Only scenario where + * timer reset won't be required is 503 with retry after. But that case will + * be handled automatically as Mobius will also reset timer when we post status + * in retry-after scenario. + */ + /* istanbul ignore next */ + if (this.sessionTimer) { + clearInterval(this.sessionTimer); + } + + const abort = await handleCallErrors( + (callError: CallError) => { + this.emit(CALL_EVENT_KEYS.CALL_ERROR, callError); + this.submitCallErrorMetric(callError); + }, + ERROR_LAYER.CALL_CONTROL, + this.callKeepaliveRetryCallback, + this.getCorrelationId(), + error, + 'handleCallEstablished', + CALL_FILE + ); + + if (abort) { + this.sendCallStateMachineEvt({type: 'E_SEND_CALL_DISCONNECT'}); + this.emit(CALL_EVENT_KEYS.DISCONNECT, this.getCorrelationId()); + this.callKeepaliveRetryCount = 0; + } + + await uploadLogs({ + correlationId: this.correlationId, + callId: this.callId, + broadworksCorrelationInfo: this.broadworksCorrelationInfo, + }); + }; + + private scheduleCallKeepaliveInterval = () => { + const loggerContext = { + file: CALL_FILE, + method: 'scheduleCallKeepaliveInterval', + }; + + this.sessionTimer = setInterval(async () => { + try { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const res = await this.postStatus(); + + log.info(`Session refresh successful`, loggerContext); + } catch (err: unknown) { + await this.handleCallKeepaliveError(err); + } + }, DEFAULT_SESSION_TIMER); + }; + /** * Handle Call Established - Roap related negotiations. * @@ -1527,83 +1607,7 @@ export class Call extends Eventing implements ICall { clearTimeout(this.sessionTimer); } - const handleTimer = () => { - this.sessionTimer = setTimeout(async () => { - try { - // eslint-disable-next-line @typescript-eslint/no-unused-vars - const res = await this.postStatus(); - - // Starting the interval again with the DEFAULT_SESSION_TIMER - clearTimeout(this.sessionTimer); - this.callKeepaliveRetryCount = 0; - this.callKeepaliveInterval = undefined; - handleTimer(); - - log.info(`Session refresh successful`, loggerContext); - } catch (err: unknown) { - const error = err; - - /* We are clearing the timer here as all are error scenarios. Only scenario where - * timer reset won't be required is 503 with retry after. But that case will - * be handled automatically as Mobius will also reset timer when we post status - * in retry-after scenario. - */ - /* istanbul ignore next */ - if (this.sessionTimer) { - clearTimeout(this.sessionTimer); - } - - const abort = await handleCallErrors( - (callError: CallError) => { - this.emit(CALL_EVENT_KEYS.CALL_ERROR, callError); - this.submitCallErrorMetric(callError); - }, - ERROR_LAYER.CALL_CONTROL, - (interval: number) => { - this.callKeepaliveRetryCount += 1; - this.callKeepaliveInterval = interval * 1000; - - // If we have reached the max retry count, do not attempt to refresh the session - if (this.callKeepaliveRetryCount === MAX_CALL_KEEPALIVE_RETRY_COUNT) { - this.callKeepaliveRetryCount = 0; - clearTimeout(this.sessionTimer); - this.sessionTimer = undefined; - this.callKeepaliveInterval = undefined; - - log.warn( - `Max call keepalive retry attempts reached for call: ${this.getCorrelationId()}`, - loggerContext - ); - - return; - } - - // Scheduling next keepalive attempt - calling handleCallEstablished - this.sendCallStateMachineEvt({type: 'E_CALL_ESTABLISHED'}); - }, - this.getCorrelationId(), - error, - 'handleCallEstablished', - CALL_FILE - ); - - if (abort) { - this.sendCallStateMachineEvt({type: 'E_SEND_CALL_DISCONNECT'}); - this.emit(CALL_EVENT_KEYS.DISCONNECT, this.getCorrelationId()); - this.callKeepaliveRetryCount = 0; - this.callKeepaliveInterval = undefined; - } - - await uploadLogs({ - correlationId: this.correlationId, - callId: this.callId, - broadworksCorrelationInfo: this.broadworksCorrelationInfo, - }); - } - }, this.callKeepaliveInterval || DEFAULT_SESSION_TIMER); - }; - - handleTimer(); + this.scheduleCallKeepaliveInterval(); } /** From 2263b008dc3014945552deadbd8838616d909400 Mon Sep 17 00:00:00 2001 From: Rajesh Kumar Date: Thu, 20 Nov 2025 19:16:23 +0530 Subject: [PATCH 4/4] fix(calling): remove unused code and clean up UTs --- .../src/CallingClient/calling/call.test.ts | 32 ++++++------------- .../calling/src/CallingClient/calling/call.ts | 7 ---- 2 files changed, 9 insertions(+), 30 deletions(-) diff --git a/packages/calling/src/CallingClient/calling/call.test.ts b/packages/calling/src/CallingClient/calling/call.test.ts index 71e0f63d66e..c8dfd8e1dda 100644 --- a/packages/calling/src/CallingClient/calling/call.test.ts +++ b/packages/calling/src/CallingClient/calling/call.test.ts @@ -1024,11 +1024,6 @@ describe('State Machine handler tests', () => { const funcSpy = jest.spyOn(call, 'postStatus').mockRejectedValue(statusPayload); - if (call['sessionTimer'] === undefined) { - /* In cases where this test is run independently/alone, there is no sessionTimer initiated - Thus we will check and initialize the timer when not present by calling handleCallEstablish() */ - call['handleCallEstablished']({} as CallEvent); - } call['handleCallEstablished']({} as CallEvent); jest.advanceTimersByTime(DEFAULT_SESSION_TIMER); @@ -1036,9 +1031,7 @@ describe('State Machine handler tests', () => { /* This is to flush all the promises from the Promise queue so that * Jest.fakeTimers can advance time and also clear the promise Queue */ - - await Promise.resolve(); - await Promise.resolve(); + await flushPromises(2); expect(clearInterval).toHaveBeenCalledTimes(1); expect(funcSpy).toBeCalledTimes(1); @@ -1065,26 +1058,19 @@ describe('State Machine handler tests', () => { } jest.advanceTimersByTime(DEFAULT_SESSION_TIMER); - await Promise.resolve(); - await Promise.resolve(); + await flushPromises(2); expect(postStatusSpy).toHaveBeenCalledTimes(1); // Now advance by 1 second for the retry-after interval jest.advanceTimersByTime(1000); - await Promise.resolve(); - await Promise.resolve(); + await flushPromises(2); expect(postStatusSpy).toHaveBeenCalledTimes(2); - expect(scheduleKeepaliveSpy).toHaveBeenCalled(); + expect(scheduleKeepaliveSpy).toHaveBeenCalledTimes(2); }); it('keepalive ends after reaching max retry count', async () => { - const resolvePromise = async () => { - await Promise.resolve(); - await Promise.resolve(); - }; - const errorPayload = ({ statusCode: 500, headers: { @@ -1105,21 +1091,21 @@ describe('State Machine handler tests', () => { // Advance timer to trigger the first failure (uses DEFAULT_SESSION_TIMER) jest.advanceTimersByTime(DEFAULT_SESSION_TIMER); - await resolvePromise(); + await flushPromises(2); // Now advance by 1 second for each of the 4 retry attempts (retry-after: 1 second each) // Need to do this separately to allow state machine to process and create new intervals jest.advanceTimersByTime(1000); - await resolvePromise(); + await flushPromises(2); jest.advanceTimersByTime(1000); - await resolvePromise(); + await flushPromises(2); jest.advanceTimersByTime(1000); - await resolvePromise(); + await flushPromises(2); jest.advanceTimersByTime(1000); - await resolvePromise(); + await flushPromises(2); // The error handler should detect we're at max retry count and stop expect(warnSpy).toHaveBeenCalledWith( diff --git a/packages/calling/src/CallingClient/calling/call.ts b/packages/calling/src/CallingClient/calling/call.ts index 5b0ded1ad5d..368e91b7f47 100644 --- a/packages/calling/src/CallingClient/calling/call.ts +++ b/packages/calling/src/CallingClient/calling/call.ts @@ -1600,13 +1600,6 @@ export class Call extends Eventing implements ICall { this.connected = true; - /* Session timers need to be reset at all offer/answer exchanges */ - if (this.sessionTimer) { - log.log('Resetting session timer', loggerContext); - - clearTimeout(this.sessionTimer); - } - this.scheduleCallKeepaliveInterval(); }