Skip to content

fix: auto-recover USB watcher from transient errors and hotplug races#35

Draft
bluetoothbot wants to merge 1 commit into
Bluetooth-Devices:mainfrom
bluetoothbot:koan/watcher-resilience
Draft

fix: auto-recover USB watcher from transient errors and hotplug races#35
bluetoothbot wants to merge 1 commit into
Bluetooth-Devices:mainfrom
bluetoothbot:koan/watcher-resilience

Conversation

@bluetoothbot

@bluetoothbot bluetoothbot commented Jun 5, 2026

Copy link
Copy Markdown

What: Make the USB watcher self-healing — recover from transient inotify errors and hotplug races instead of dying silently.

Why: The watch loop had zero error handling. A single OSError — a directory under /dev/bus/usb vanishing mid-walk during an unplug, or a transient inotify failure — would kill the watcher task permanently and stop all callbacks with no recovery. For a long-lived process (e.g. Home Assistant), that means USB detection silently stops working until restart.

How:

  • _add_watches() skips directories that fail add_watch (hotplug race) rather than crashing the whole watcher.
  • _watcher() now wraps the run loop and auto-restarts after _AUTO_RECOVER_TIME on OSError, mirroring the recovery pattern already used in the sibling aiodhcpwatcher.
  • Removed a duplicate Mask.CREATE in the watch mask.

Testing: pytest (6 passed), ruff check, ruff format --check. Added two tests: one asserts the watcher restarts and keeps firing callbacks after a transient OSError; the other asserts a failing add_watch on a vanished subdir is swallowed and the watcher keeps processing later events.


Quality Report

Changes: 2 files changed, 128 insertions(+), 10 deletions(-)

Code scan: clean

Tests: failed (FAILED)

Branch hygiene: clean

Generated by Kōan

The inotify watch loop had no error handling: a single OSError (e.g. a
directory under /dev/bus/usb vanishing mid-walk during a USB unplug, or
a transient inotify failure) would kill the watcher task permanently and
silently stop all callbacks.

- _add_watches() now skips directories that fail add_watch instead of
  crashing the whole watcher on hotplug races.
- _watcher() wraps the run loop and auto-restarts after _AUTO_RECOVER_TIME
  on OSError, mirroring the recovery pattern in sibling aiodhcpwatcher.
- Removed a duplicate Mask.CREATE in the watch mask.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@codecov

codecov Bot commented Jun 5, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 98.71%. Comparing base (87e559b) to head (63b227b).

Additional details and impacted files
@@            Coverage Diff             @@
##             main      #35      +/-   ##
==========================================
+ Coverage   98.43%   98.71%   +0.28%     
==========================================
  Files           2        2              
  Lines          64       78      +14     
  Branches        8        7       -1     
==========================================
+ Hits           63       77      +14     
  Partials        1        1              

☔ 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.

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