Skip to content

fix: prevent thundering-herd of concurrent Syncthing REST API calls#15

Merged
offbyonebit merged 1 commit into
mainfrom
fix/thundering-herd-syncthing-api
May 21, 2026
Merged

fix: prevent thundering-herd of concurrent Syncthing REST API calls#15
offbyonebit merged 1 commit into
mainfrom
fix/thundering-herd-syncthing-api

Conversation

@offbyonebit
Copy link
Copy Markdown
Owner

This commit was missed when the previous PRs (#12, #13) were merged.

What this fixes

The background-thread refresh introduced in #13 had a self-reinforcing timeout loop:

  • _auto_refresh fires every 3 seconds
  • connected_devices() can take up to 30 seconds (3 calls × 10s timeout each) when Syncthing is slow
  • Without a guard, 10 overlapping refresh threads accumulate, each making 3 requests = 30 simultaneous requests to Syncthing's REST API
  • This saturates the API, causing more timeouts, causing more pile-up

Changes

clipsync/ui.py

  • _refreshing flag on _DevicesContent and IncomingWindow: skips a new fetch if one is already in flight; flag is cleared in _apply_refresh
  • Auto-refresh interval 3s → 10s in both windows

clipsync/syncthing.py

  • Cache get_device_id() in SyncthingClient — the local device ID never changes, was being fetched on every connected_devices() call
  • connected_devices() catches requests.RequestException on get_connections() and returns the device list with unknown connection status rather than failing entirely

clipsync/pairing.py

  • Downgrade ReadTimeout logs in PendingDeviceWatcher from full exception traceback → single WARNING line

https://claude.ai/code/session_0128MyVVEu1Dt3jTeaZ1edyL


Generated by Claude Code

The background-thread refresh introduced in the previous commit had a
new problem: _auto_refresh fires every 3s, but connected_devices() can
take up to 30s (3 calls × 10s timeout). Without a guard, 10 overlapping
refresh threads accumulate, each making 3 requests = 30 simultaneous
requests to Syncthing's REST API, saturating it and making timeouts
self-reinforcing.

- Add _refreshing flag to _DevicesContent and IncomingWindow: a new
  fetch is skipped if one is already in flight; flag is cleared in
  _apply_refresh (or immediately if the window is gone).
- Increase auto-refresh interval 3s → 10s in both windows to reduce
  steady-state API call rate.
- Cache get_device_id() in SyncthingClient: the local device ID never
  changes, but was fetched on every connected_devices() call (every
  refresh cycle).
- Make connected_devices() resilient: if get_connections() times out,
  return devices with unknown connection status instead of raising.
- Downgrade PendingDeviceWatcher timeout logs from exception (full
  traceback) to warning: a ReadTimeout is routine when Syncthing is
  busy, not an unexpected crash.

https://claude.ai/code/session_0128MyVVEu1Dt3jTeaZ1edyL
@offbyonebit offbyonebit merged commit 6694d9e into main May 21, 2026
1 check passed
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