Skip to content

feat: add exponential backoff and attempt limits to BLE reconnection#18

Open
regulapati-n wants to merge 1 commit into
b-nnett:mainfrom
regulapati-n:feat/ble-reconnect-backoff
Open

feat: add exponential backoff and attempt limits to BLE reconnection#18
regulapati-n wants to merge 1 commit into
b-nnett:mainfrom
regulapati-n:feat/ble-reconnect-backoff

Conversation

@regulapati-n

Copy link
Copy Markdown

Summary

Added exponential backoff and a 10-attempt circuit breaker to the BLE reconnection logic in GooseBLEClient. Previously, the app reconnected immediately and indefinitely after any disconnect, which can drain battery when the peripheral is out of range.

Changes Made

  1. GooseBLEClient.swift: Added reconnection state properties (reconnectAttemptCount, reconnectNextRetryAt, reconnectBackoffWorkItem) and backoff constants (1.0s base delay, doubling multiplier, capped at 60s, max 10 attempts).
  2. GooseBLEClient+Commands.swift: Added scheduleReconnectWithBackoff(_:reason:) and resetReconnectBackoff().
  3. GooseBLEClient+CentralDelegate.swift: Integrated backoff scheduling into didDisconnectPeripheral and didFailToConnect, and reset on didConnect.
  4. DeviceView.swift: Added a ReconnectBackoffBanner showing countdown and attempt count, with manual override buttons ("Retry Now" and "Stop Retrying").

Replace immediate, unlimited BLE reconnection with exponential backoff
(1s → 2s → 4s → 8s → 16s → 32s → 60s cap) and a 10-attempt limit.

Previously, when a remembered WHOOP device disconnected, the app would
immediately call connect() again with no delay and no upper bound. This
caused rapid reconnect loops that drain battery on both phone and band,
especially when the device is out of range.

Changes:
- GooseBLEClient.swift: add reconnectAttemptCount, reconnectNextRetryAt
  @published properties and backoff constants (base 1s, multiplier 2x,
  max 60s, 10 attempts)
- GooseBLEClient+Commands.swift: add scheduleReconnectWithBackoff() with
  exponential delay calculation and resetReconnectBackoff(); wire reset
  into clearRememberedDevice()
- GooseBLEClient+CentralDelegate.swift: replace immediate reconnect in
  didDisconnectPeripheral with backoff; add backoff retry in
  didFailToConnect; reset counter in didConnect on success
- DeviceView.swift: add ReconnectBackoffBanner showing attempt count,
  countdown timer, and Retry Now / Stop Retrying buttons

Diagnostic log events added:
- reconnect.backoff.scheduled (attempt, delay, reason)
- reconnect.backoff.reset (previous attempt count)
- reconnect.gave_up (after max attempts exhausted)
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.

1 participant