Skip to content

Stop the Expert MQTT client reconnecting in a hot loop - #8631

Merged
cstns merged 1 commit into
mainfrom
8630-expert-mqtt-reconnect-churn
Sep 23, 2026
Merged

cstns merged 1 commit into
mainfrom
8630-expert-mqtt-reconnect-churn

Conversation

@cstns

@cstns cstns commented Sep 22, 2026

Copy link
Copy Markdown
Contributor

Part of #8630, which the follow-up PR closes.

The Expert's MQTT connection was reconnecting in a hot loop whenever a link connected and then dropped again a few seconds later, because reconnectAttempt got cleared on every successful connect. One user in production went through 11 reconnects in under 3 minutes that way.

Three changes:

  • connect now records when the connection came up, and scheduleReconnect only clears the attempt counter once it has held for 30s. A flapping link walks 1s, 2s, 4s up to the existing 30s cap instead of retrying at 1s forever.
  • _dispatch was calling observer handlers without catching, so an async handler that rejected escaped as an unhandled rejection. That is where the Connection closed errors in Sentry came from: mqtt.js flushes in-flight packets when a client is torn down during a reconnect, and nothing was listening. It now catches sync throws and attaches a handler to any promise a handler returns, staying quiet for teardown errors and warning on anything else.
  • the fire-and-forget abort publish gets a catch, and the expert:status-message ack gets the try/catch its sibling branches already had.

Publishes and subscribes still reject honestly rather than being resolved on teardown, since swallowing them inside the service would hide real delivery failures too.

Four tests added. Two of them fail without the fix, the other two are regression guards that passed either way.

Deliberately not in here: every drop currently posts a disconnect message and every recovery posts a greeting, so a short blip gets narrated twice. Suppressing that needs a call on how long an outage should last before the Expert mentions it at all.

reconnectAttempt was cleared on every successful connect, so a link that
connected and then dropped seconds later never backed off and kept retrying at
the initial delay. Record when the connection came up instead, and only clear
the counter once it has held for STABLE_CONNECTION_MS.

_dispatch also invoked observer handlers without catching, so any async handler
that rejected escaped as an unhandled rejection. That is how in-flight packets
flushed by a client teardown surfaced as "Connection closed". It now catches
sync throws and attaches a handler to any promise a handler returns, staying
quiet for teardown errors and warning on everything else.

Also attaches a catch to the fire-and-forget abort publish and gives the
expert:status-message ack the try/catch its sibling branches already have.
@cstns cstns self-assigned this Sep 22, 2026
@cstns
cstns marked this pull request as ready for review September 22, 2026 14:59
@codecov

codecov Bot commented Sep 22, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 77.25%. Comparing base (567f824) to head (06ba103).

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #8631   +/-   ##
=======================================
  Coverage   77.25%   77.25%           
=======================================
  Files         466      466           
  Lines       25131    25131           
  Branches     6690     6690           
=======================================
  Hits        19414    19414           
  Misses       5717     5717           
Flag Coverage Δ
backend 77.25% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@cstns
cstns merged commit 88c9b75 into main Sep 23, 2026
29 checks passed
@cstns
cstns deleted the 8630-expert-mqtt-reconnect-churn branch September 23, 2026 10:50

This branch was successfully deployed

1 active deployment
staging 06ba103d Deployed Sep 23, 2026 by cstns via Remove application #11878
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants