Skip to content

Reliable shutdown on Windows + lelab --stop#46

Merged
nicolas-rabault merged 3 commits into
huggingface:mainfrom
nobullryder:launcher-reliability
Jul 6, 2026
Merged

Reliable shutdown on Windows + lelab --stop#46
nicolas-rabault merged 3 commits into
huggingface:mainfrom
nobullryder:launcher-reliability

Conversation

@nobullryder

Copy link
Copy Markdown
Contributor

Problem

On Windows, stopping lelab (Ctrl-C / closing the terminal) often leaves the uvicorn and Vite child processes alive, which keeps port :8000 — and any open camera handles — held. The next lelab then fails to bind, or a camera won't open because the previous run never released it.

What this does

  • lelab --stop — finds and terminates a running LeLab and its child process tree, freeing the port.
  • Clean process-tree teardown on exit (psutil, with a Windows taskkill /T fallback) so the uvicorn/Vite children and their handles are actually released.
  • Pre-flight port checks with an actionable message ("…run lelab --stop to free it") instead of an opaque bind error, plus a readiness wait before opening the browser.

Tests

tests/test_scripts_lelab.py covers the stop / teardown / port-check paths with mocked psutil + subprocess (no real processes spawned).

🤖 Generated with Claude Code

On Windows, stopping LeLab (Ctrl-C / closing the terminal) often leaves the
uvicorn and Vite child processes alive, which keeps port :8000 — and any open
camera handles — held. The next `lelab` then fails to bind, or a camera won't
open because the previous run never released it.

- `lelab --stop`: find and terminate a running LeLab and its child process tree,
  freeing the port.
- Clean process-tree teardown on exit (psutil, with a Windows `taskkill /T`
  fallback) so the uvicorn/Vite children and their handles are actually released.
- Pre-flight port checks with an actionable message ("…run `lelab --stop` to free
  it") instead of an opaque bind error, plus a readiness wait before opening the
  browser.

Tests in tests/test_scripts_lelab.py cover the stop / teardown / port-check paths
with mocked psutil + subprocess (no real processes spawned).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Comment thread lelab/scripts/lelab.py Outdated
Comment thread lelab/scripts/lelab.py Outdated
Comment thread lelab/scripts/lelab.py Outdated
Comment thread lelab/scripts/lelab.py Outdated

@nicolas-rabault nicolas-rabault left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you @nobullryder for this contribution.
Here are some changes requests that could improve it.

nobullryder and others added 2 commits July 2, 2026 09:14
- The install_signal_handlers override + os._exit(0) path now only
  applies on Windows (os.name == "nt"); macOS/Linux keep uvicorn's
  native handlers, and timeout_graceful_shutdown=2 is restored so the
  prod server gracefully drains as it did before this PR.
- _monitor_processes no longer coerces a clean child exit (0) to exit
  code 1; since it's inside the `returncode is not None` branch it can
  raise SystemExit(returncode) directly.
- _fail is annotated -> NoReturn, dropping the two unreachable
  `raise AssertionError("unreachable")` lines.
- The dev-mode SIGINT/SIGTERM handler just raises SystemExit(0);
  teardown is owned solely by _run_dev's `except BaseException`
  (also removed the same double pass from _monitor_processes).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@nicolas-rabault nicolas-rabault self-requested a review July 6, 2026 09:05

@nicolas-rabault nicolas-rabault left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very nice, thank you 🤗

@nicolas-rabault nicolas-rabault merged commit 46a0688 into huggingface:main Jul 6, 2026
2 checks passed
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