Skip to content

Fix stop() leaving ghost threads that block reconnection#192

Open
Fernandosnulerin wants to merge 1 commit intotwrecked:masterfrom
Fernandosnulerin:fix/stop-cleanup-threads
Open

Fix stop() leaving ghost threads that block reconnection#192
Fernandosnulerin wants to merge 1 commit intotwrecked:masterfrom
Fernandosnulerin:fix/stop-cleanup-threads

Conversation

@Fernandosnulerin
Copy link
Copy Markdown

Summary

Fixes #71.

When stop() is called, the backend event stream thread keeps running — it holds stale SSE/MQTT connections and attempts its own re-logins, making it impossible to create a new PyArlo instance in the same process. The only recovery is killing the entire process.

Three bugs contributed:

  1. PyArlo.stop() never stops the backend — it only calls self._be.logout() when logout=True. With the default logout=False, the event stream thread is never stopped.

  2. The re-login loop ignores the stop flag_event_main() has while not self._logged_in without checking _stop_thread. Once the event stream drops, the thread enters an infinite re-login loop that cannot be interrupted by stop().

  3. _event_stop_loop() doesn't wake blocked threads — it sets the flag but doesn't call notify_all(), so threads blocked on self._lock.wait(5) don't see it for up to 5 seconds.

Changes

  • Add ArloBackEnd.stop() — signals the event thread, disconnects the MQTT/SSE client, and joins the thread with a 10s timeout
  • Update PyArlo.stop() to always call self._be.stop() (or .logout() when logout=True)
  • Check _stop_thread in the re-login loop so stop requests are honoured immediately
  • Call self._lock.notify_all() in _event_stop_loop() to wake blocked threads

Motivation

Any long-running application that needs to reconnect to Arlo (e.g. Home Assistant, or any polling service) hits this — after the session goes stale, creating a new PyArlo instance in the same process fails because the old instance's ghost threads compete for the same Arlo account, triggering Cloudflare 403/500 blocks. The standard workaround has been to restart the entire process, but proper cleanup in stop() makes in-process reconnection work reliably.

Test plan

  • Call arlo.stop() then verify ArloBackgroundWorker and ArloEventStream threads are no longer alive
  • Call arlo.stop(logout=True) then create a new PyArlo() in the same process — should connect cleanly
  • Call arlo.stop() while the event thread is in the re-login loop — thread should exit promptly

🤖 Generated with Claude Code

Fixes twrecked#71.

When stop() was called (without logout=True), it stopped the background
worker and media library but left the backend event stream thread
running. The abandoned thread would hold stale SSE/MQTT connections and
attempt its own re-logins, interfering with any new PyArlo instance
created in the same process. This made in-process reconnection
impossible — the only recovery was killing the entire process.

Three bugs contributed:

1. PyArlo.stop() only called self._be.logout() when logout=True.
   With the default logout=False, the backend was never stopped at all.

2. The re-login loop in _event_main() — `while not self._logged_in` —
   did not check _stop_thread. Once the event stream dropped and the
   thread entered the re-login loop, setting _stop_thread had no effect
   until a login succeeded (which it never would with a stale session).

3. _event_stop_loop() set the flag but did not notify threads blocked on
   self._lock.wait(5), causing up to a 5-second delay before the thread
   noticed the stop request.

Changes:
- Add ArloBackEnd.stop() that signals the event thread, disconnects the
  client, and joins the thread with a 10s timeout.
- Update PyArlo.stop() to always call self._be.stop() (or .logout()
  when logout=True).
- Check _stop_thread in the re-login loop so stop requests are honoured
  promptly.
- Call self._lock.notify_all() in _event_stop_loop() to wake any thread
  blocked on the condition variable.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
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.

Connection with the arlo account not stopping

1 participant