Skip to content

fix(machine): rebuild a cleaned-up driver instead of reusing it - #635

Merged
knipknap merged 2 commits into
barebaric:mainfrom
medoix:fix/ruida-reconnect-after-switch
Oct 26, 2026
Merged

knipknap merged 2 commits into
barebaric:mainfrom
medoix:fix/ruida-reconnect-after-switch

Conversation

@medoix

@medoix medoix commented Oct 26, 2026 •

Copy link
Copy Markdown
Contributor

What does this PR change?

Switching the active machine away from a Ruida machine and back left it stuck at status Unknown. Every reconnect attempt failed with RPA reconnect attempt failed: Direct mode requires the direct backend until Rayforge was restarted (or TUI mode was toggled to force a rebuild).

The cause is in MachineController. MachineManager.set_active_machine() disconnects the previous machine, and controller.disconnect() runs driver.cleanup() and then queues rebuild_driver(). With the driver class and arguments unchanged, rebuild_driver() asked the cleaned-up driver to absorb the settings through update_settings(). The Ruida adapter opts in, so it returned True and the machine kept a driver whose backend cleanup() had already released.

rebuild_driver() now only offers update_settings() to a driver that is still set up (did_setup). A cleaned-up driver is always replaced by a fresh one, which is what the queued rebuild after a disconnect intends.

Why did you choose this specific architectural approach?

did_setup is already the base driver's record of whether setup() has run, and Driver.cleanup() clears it, so the controller can tell a live driver from a released one without knowing anything about the driver. That keeps the fix in the one place that decides between reuse and rebuild, and covers any driver that opts in to update_settings(), not only the Ruida adapter.

Alternatives considered:

  • Recreating the backend inside the Ruida adapter when _backend is None. That fixes only one driver and leaves update_settings() accepting settings on an object that has been cleaned up.
  • Making the adapter's update_settings() return False after cleanup. Same problem: every opt-in driver would need the same guard.

How did you manually test this locally?

Two Ruida lasers configured as separate machines: an RDC8445S over TCP (Wi-Fi) and an RDLC-V26.60.20 controller over UDP, both with auto-connect on.

  1. Start Rayforge with machine A active and wait for it to connect.
  2. Switch to machine B in the header dropdown and wait for it to connect.
  3. Switch back to machine A. Before: status stays Unknown and the log repeats "Direct mode requires the direct backend" every 5 s. After: A gets a new driver ("RPA adapter configured for direct mode") and logs "RPA connected" about a second later.
  4. Repeat the round trip; both machines reconnect every time.

Tests: tests/machine/models/test_machine_controller.py gains a test that disconnects an opt-in driver and checks it is replaced rather than reused; it fails without the change. The machine and Ruida driver test folders pass apart from test_end_failed_carries_message and test_failed_job_reports_error_message, which fail the same way on unmodified main in my environment.

Checklist

  • I am not an AI. I have manually read the code and understand it.
  • I take full responsibility for the quality and architectural fit of
    this code.
  • I agree to publish this code under the MIT license.

Switching the active machine disconnects the previous one, which runs
driver.cleanup() and then queues rebuild_driver(). With the driver
class and arguments unchanged, rebuild_driver() asked the cleaned-up
driver to absorb the settings via update_settings(). A driver that
opts in (the Ruida adapter) accepted, so the machine kept a driver
whose backend had been released. Switching back to that machine then
failed every reconnect ("Direct mode requires the direct backend")
and its status stayed Unknown until Rayforge was restarted.

Only offer update_settings() to a driver that is still set up, so a
cleaned-up driver is always replaced by a fresh one.
@medoix
medoix force-pushed the fix/ruida-reconnect-after-switch branch from eea8894 to 7ed051b Compare October 26, 2026 03:17
@medoix
medoix marked this pull request as ready for review October 26, 2026 03:22
@knipknap
knipknap merged commit 7525a0d into barebaric:main Oct 26, 2026
32 checks passed
@knipknap

Copy link
Copy Markdown
Contributor

Thanks for the fix!

This branch was previously deployed

1 inactive deployment
pypi — d6673bd4 Deployed Oct 26, 2026 by knipknap via Build and Publish Wheel #2491
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