Skip to content

bugfix: fix threading races and concurrency in moonrakerComm/RepeatedTimer - #211

Merged
gmmcosta15 merged 18 commits into
devfrom
bugfix/threading-concurrency
Sep 24, 2026
Merged

gmmcosta15 merged 18 commits into
devfrom
bugfix/threading-concurrency

Conversation

@gmmcosta15

Copy link
Copy Markdown
Collaborator
  • Feature
  • Bug fix
  • Code refactor
  • Documentation

Description

  • Move connected, connecting, _reconnect_count, callback_table from class-level to __init__ to prevent shared state across instances.
  • Add _state_lock (RLock) and _request_lock guarding all reads/writes to those vars.
  • Fix mutable default argument params={} → params=None in send_request.
  • Fix unbound super() in OneShotTokenError.
  • Guard _retry_timer with None check before stopTimer/startTimer; stop existing timer in try_connection before creating a new one (prevents orphaned threads).
  • Replace sendEvent → postEvent for safe cross-thread event delivery.
  • Wrap json.loads in try/except; use .get() on all external response dicts.
  • Add klippy startup/disconnected retry cap (30 attempts) to prevent infinite reconnect loop.
  • Add join(timeout=self.timeout+1) on _wst to avoid indefinite block on shutdown.
  • Fix RepeatedTimer: inverted stopEvent semantics (set=stop, clear=running).

Motivation

The WebSocket layer had multiple threading races and incorrect cross-thread event dispatch causing UI freezes and crashes on Pi hardware. RepeatedTimer had inverted stop-event logic causing timers to never stop correctly. These are the root-cause fixes for the most severe class of bugs in #200.

@HugoCLSC

Copy link
Copy Markdown
Member

Solid PR, solves a bunch of probable issues

@gmmcosta15
gmmcosta15 merged commit 2dc7af0 into dev Sep 24, 2026
8 checks passed
@gmmcosta15
gmmcosta15 deleted the bugfix/threading-concurrency branch September 24, 2026 09:16
gmmcosta15 added a commit that referenced this pull request Sep 28, 2026
…tton (#339)

# Description

- [ ] Feature
- [x] Bug fix
- [ ] Code refactor
- [ ] Documentation

ConnectionPage now shows only while Klipper/Moonraker is down. It keeps
retrying on its own and returns to the main window when Klipper is
ready. The only buttons left are Restart Klipper and Restart Firmware.

- Websocket: one retry timer every 3s with no cap, stopped only by an
intentional disconnect.
- Klippy: server.info is polled every 2s in any non-ready state with no
cap. The state signal is sent only when the state changes, and the
tracked state is reset on reconnect and on `notify_klippy_disconnected`.
- Retry button removed from ConnectionPage.
- mainWindow: removed the duplicate `klippy_state_signal` connection.
- mainWindow: the automatic klipper service restart waits 15s in
"disconnected", so a RESTART/SAVE_CONFIG or systemd's own restart
(RestartSec=10) no longer triggers it.

# Motivation

After #211 the page froze: the websocket gave up after 3 attempts, and
the Klippy poll stopped after 60s, which is shorter than Klipper's 90s
MCU connect window.

# Tests

- Unit tests added for moonrakerComm, mainWindow and ConnectionPage.
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