Skip to content

fix(calling): handle 409 error for keepalive - #5172

Open
rarajes2 wants to merge 1 commit into
webex:nextfrom
rarajes2:calling-handle-409
Open

fix(calling): handle 409 error for keepalive#5172
rarajes2 wants to merge 1 commit into
webex:nextfrom
rarajes2:calling-handle-409

Conversation

@rarajes2

@rarajes2 rarajes2 commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

COMPLETES #< SPARK-832708 >

This pull request addresses

When Mobius answers a keepalive (device_status) with 409 Conflict, the device registration
is gone but the same user still holds an active registration elsewhere — typically calling
opened in a second browser tab, which superseded this one. Previously a 409 fell through to the
default branch of handleRegistrationErrors, so the SDK re-registered. That unregistered the
other tab, which then re-registered and unregistered this one, producing a registration
ping-pong between tabs.

by making the following changes

A 409 on keepalive is now a hard stop: the keepalive worker is terminated, no re-registration is
attempted, the Mobius WebSocket is closed, and the app is notified that its session was
superseded.

  • register.ts — the KEEPALIVE_FAILURE branch short-circuits to a new
    handle409KeepaliveFailure before handleRegistrationErrors runs, so no retry, failover, or
    restore path can execute. The worker is stopped up front (before waiting on the shared mutex)
    so no further keepalive can be sent.
  • performRegistrationDownCleanupperformHardStopCleanup(caller, hardStop), now shared with
    the 409 path. A HardStop discriminated union (registration/types.ts) makes it impossible to
    signal a superseded session without the LineError the consumer receives, and its
    HARD_STOP_REASON values double as the log label. Teardown is unchanged: timers cleared,
    transient flags and failover cache reset, status INACTIVE, WebSocket closed with the existing
    permanent code {code: 3050, reason: 'done (permanent)'}.
  • Observability: submits the existing KEEPALIVE_ERROR / KEEPALIVE_FAILURE registration metric
    and calls uploadLogs().

Public API (additive)

  • New LINE_EVENTS.SESSION_SUPERSEDED = 'session_superseded', typed in LineEventTypes as
    (error: LineError) => void.
  • New ERROR_TYPE.SESSION_SUPERSEDED and ERROR_CODE.CONFLICT = 409.
  • For backward compatibility unregistered still fires first, followed by session_superseded
    with the error. Line.lineEmitter re-emits it through the same guarded branch as error.

No existing event, payload, or status transition changed. Keepalive 404 / 429 / 5xx and the
registration, restoration, failover, and failback paths are untouched — the short-circuit is
scoped to the keepalive worker's failure branch only.

Notes

The LineError message comes from a new SESSION_SUPERSEDED_MESSAGE constant rather than
Mobius's data.message: the keepalive worker's failure envelope forwards only headers/status, and
adding the response body would have silently changed the 403 device-limit branch in
handleRegistrationErrors. Detection relies solely on the status code.

Change Type

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation update
  • Tooling change
  • Internal code refactor

The following scenarios were tested

Vidcast - https://app.vidcast.io/share/d6bda2af-24a9-4cee-ab69-d9a2da283aa3

The GAI Coding Policy And Copyright Annotation Best Practices

  • GAI was not used (or, no additional notation is required)
  • Code was generated entirely by GAI
  • GAI was used to create a draft that was subsequently customized or modified
  • Coder created a draft manually that was non-substantively modified by GAI (e.g., refactoring was performed by GAI on manually written code)
  • Tool used for AI assistance (GitHub Copilot / Other - specify)
    • Github Copilot
    • Other - Cursor
  • This PR is related to
    • Feature
    • Defect fix
    • Tech Debt
    • Automation

I certified that

  • I have read and followed contributing guidelines
  • I discussed changes with code owners prior to submitting this pull request
  • I have not skipped any automated checks
  • All existing and new tests passed
  • I have updated the documentation accordingly

Make sure to have followed the contributing guidelines before submitting.

@rarajes2
rarajes2 requested a review from a team as a code owner August 17, 2026 08:50
@rarajes2 rarajes2 added the validated If the pull request is validated for automation. label Aug 17, 2026

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 65f0ca8bb0

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +441 to +444
await this.performHardStopCleanup(METHODS.HANDLE_409_KEEPALIVE_FAILURE, {
reason: HARD_STOP_REASON.SESSION_SUPERSEDED,
error: lineError,
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge End active calls when the session is superseded

When a second tab or device supersedes a registration during an active call, this path marks the line inactive and disconnects its transport without ending the call retained by CallManager. Unlike handleRegistrationDownEvent(), which explicitly calls activeCall?.end(), the 409 path leaves the call, media connection, and call timers alive even though no further Mobius events can arrive, so consumers may continue displaying a stale established call. End the active call(s) before performing this hard-stop cleanup.

Useful? React with 👍 / 👎.

@aws-amplify-us-east-2

Copy link
Copy Markdown

This pull request is automatically being deployed by Amplify Hosting (learn more).

Access this pull request here: https://pr-5172.d3m3l2kee0btzx.amplifyapp.com

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

validated If the pull request is validated for automation.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant