Skip to content

Update using-solid-node.rst#7

Open
felipesanches wants to merge 1 commit into
LibreSolid:mainfrom
felipesanches:patch-1
Open

Update using-solid-node.rst#7
felipesanches wants to merge 1 commit into
LibreSolid:mainfrom
felipesanches:patch-1

Conversation

@felipesanches

Copy link
Copy Markdown

No description provided.

lfagundes added a commit that referenced this pull request Jul 16, 2026
…b viewer

Bug (improvements.md #7): `solid develop` respawns a fresh Builder
subprocess on every save. When re-importing edited project source
raised at module level (NameError, SyntaxError, ImportError, ...),
Builder._start() caught the exception and awaited self.file_changed --
but the watchdog Observer is only scheduled *after* a successful
load_node()+assemble(), which is exactly what had just failed. So the
future could never resolve: the builder subprocess hung forever with
nothing watching, and Develop.handle()'s `builder_proc.join()` blocked
forever too, silently freezing the whole develop loop (no further
saves were ever picked up).

Worse, on the very next loop iteration Develop.handle() unconditionally
restarts the web viewer ("Restarting WEB"). WebViewer.__init__ calls
load_node(path) itself with no error handling, so if the project was
still broken at that moment the web viewer subprocess crashed outright
-- taking the browser-facing server, the reload websocket and the
/_build_error endpoint down with it.

Fix:
- Builder gets an `is_reload` flag. Develop.handle() passes False only
  for the very first attempt of a `solid develop` invocation and True
  for every attempt afterwards (every attempt the watch loop
  triggers). A load/assemble exception on a reload attempt now falls
  back to watching the whole project directory recursively (filtered
  to .py, ignoring __pycache__, since the precise file list is exactly
  what failed to be discovered), writes the error to the existing
  errors.json channel via report_error(), and exits cleanly the moment
  a fix is saved so Develop respawns and retries. On the very first
  (non-reload) attempt the old semantics are kept intentionally
  fragile, but no longer hang: a broken project logs one clean line
  and exits non-zero instead of dumping a traceback and hanging
  forever.
- Develop.handle() now checks the first builder_proc's exitcode: if
  that initial attempt fails, it tears down whatever else it started
  (web/web-dev/openscad) and exits the whole command, instead of
  looping around and treating the next attempt as a recoverable
  reload.
- WebViewer.__init__ now guards load_node()+NodeAPI construction: a
  broken project no longer crashes the webserver subprocess. It logs
  locally and simply skips mounting /node for that instance -- the
  existing /_build_error endpoint (fed by Builder's errors.json) and
  the reload websocket stay up, and the next successful reload
  restarts the viewer with a working node again.
- Also guards Builder.on_modified's Future.set_result against a second
  filesystem event arriving before the first is consumed.

Tests (TDD, verified failing against the pre-fix code by stashing the
source changes and re-running):
- tests/test_builder_reload_resilience.py: drives the real Builder
  (real watchdog Observer, real asyncio loop) against a scratch copy of
  tests/flat_project, each attempt as a real multiprocessing.Process
  (so sys.exit() only ends that child, matching production). Covers a
  NameError reload and a SyntaxError reload staying alive and
  surfacing the error, recovery clearing the error and building after
  a fix, and the startup (non-reload) case exiting promptly instead of
  hanging.
- tests/test_manager_develop.py: unit tests that Develop.handle() flags
  only the first builder invocation as non-reload, and that a failed
  first attempt tears down the other processes and exits.
- tests/test_web_viewer.py: WebViewer construction, /_build_error and
  the reload websocket all survive a load_node() failure.

Gates: `.venv/bin/python -m pytest tests/ -q` -- 169 passed. Gearbox
canary (all 8 node files under examples/gearbox/root) -- each ends `0
failed`. Manual verification: ran `solid develop` against a scratch
copy of tests/flat_project, broke simple_pipe.py with a module-level
NameError mid-edit, confirmed the process stayed alive and
/_build_error surfaced the traceback while /node/ kept responding,
fixed the file, and confirmed /_build_error cleared and /node/ +
the STL route served the rebuilt model again -- server never dropped
connection throughout.

Co-Authored-By: Claude Fable 5 <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.

1 participant