daemon: survive BLE adapter removal and auto-restart on crash
Pulling the USB Bluetooth dongle made BleakScanner raise from inside the main loop; the exception propagated out of daemon_main, the bg thread died, and the tray froze on its last state with no recovery (reported: "daemon crashed and doesn't come back"). Two layers of hardening: 1. main() loop now wraps scan+connect in try/except — adapter-gone errors are logged, the tray shows Scanning, and it backs off and retries, so replugging the adapter recovers automatically. CancelledError is re-raised. 2. The tray supervises the asyncio loop: an unexpected crash is logged and the loop is RESTARTED after a backoff, gated by a quit_evt so Quit still stops cleanly (and call_soon_threadsafe is guarded against a closed loop). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -596,34 +596,51 @@ async def main(tray_state=None) -> None:
|
||||
search_backoff = 1 # caps at 60s — gentle, for a device that is genuinely absent/off
|
||||
reconnect_backoff = 1 # caps at RECONNECT_BACKOFF_CAP — fast, to clear the 120s SLA after a drop
|
||||
while not stop_event.is_set():
|
||||
device = await scan_for_device()
|
||||
if not device:
|
||||
# Slow-search regime: device was not found by scan — back off gently
|
||||
try:
|
||||
device = await scan_for_device()
|
||||
if not device:
|
||||
# Slow-search regime: device was not found by scan — back off gently
|
||||
if tray_state:
|
||||
tray_state.set_scanning()
|
||||
log(f"Device not found, retrying in {search_backoff}s...")
|
||||
try:
|
||||
await asyncio.wait_for(stop_event.wait(), timeout=search_backoff)
|
||||
except asyncio.TimeoutError:
|
||||
pass
|
||||
search_backoff = _next_backoff(search_backoff, 60)
|
||||
continue
|
||||
|
||||
ok = await connect_and_run(device, stop_event, tray_state)
|
||||
if not ok:
|
||||
# Fast-reconnect regime: had/attempted a link that dropped — retry quickly
|
||||
if tray_state:
|
||||
tray_state.set_scanning()
|
||||
log(f"Connection lost, reconnecting in {reconnect_backoff}s...")
|
||||
try:
|
||||
await asyncio.wait_for(stop_event.wait(), timeout=reconnect_backoff)
|
||||
except asyncio.TimeoutError:
|
||||
pass
|
||||
reconnect_backoff = _next_backoff(reconnect_backoff, RECONNECT_BACKOFF_CAP)
|
||||
else:
|
||||
# Successful session — reset reconnect counter to floor; search_backoff also reset
|
||||
reconnect_backoff = 1
|
||||
search_backoff = 1
|
||||
except asyncio.CancelledError:
|
||||
raise
|
||||
except Exception as e:
|
||||
# The whole BLE adapter can disappear (USB dongle unplugged) — bleak/
|
||||
# WinRT then raises from the scan or the connect. Never let that kill
|
||||
# the loop: log, show Scanning, back off, and keep retrying so
|
||||
# replugging the adapter recovers on its own, no manual restart
|
||||
# (field SC: pulled the dongle -> daemon crashed and stayed down).
|
||||
if tray_state:
|
||||
tray_state.set_scanning()
|
||||
log(f"Device not found, retrying in {search_backoff}s...")
|
||||
log(f"BLE error ({type(e).__name__}: {e}); retrying in {search_backoff}s...")
|
||||
try:
|
||||
await asyncio.wait_for(stop_event.wait(), timeout=search_backoff)
|
||||
except asyncio.TimeoutError:
|
||||
pass
|
||||
search_backoff = _next_backoff(search_backoff, 60)
|
||||
continue
|
||||
|
||||
ok = await connect_and_run(device, stop_event, tray_state)
|
||||
if not ok:
|
||||
# Fast-reconnect regime: had/attempted a link that dropped — retry quickly
|
||||
if tray_state:
|
||||
tray_state.set_scanning()
|
||||
log(f"Connection lost, reconnecting in {reconnect_backoff}s...")
|
||||
try:
|
||||
await asyncio.wait_for(stop_event.wait(), timeout=reconnect_backoff)
|
||||
except asyncio.TimeoutError:
|
||||
pass
|
||||
reconnect_backoff = _next_backoff(reconnect_backoff, RECONNECT_BACKOFF_CAP)
|
||||
else:
|
||||
# Successful session — reset reconnect counter to floor; search_backoff also reset
|
||||
reconnect_backoff = 1
|
||||
search_backoff = 1
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
Reference in New Issue
Block a user