Skip to content

[staging CI] unslothai/unsloth#8170 - #217

Closed
danielhanchen wants to merge 6 commits into
mainfrom
pr-8170-xplat-ci
Closed

danielhanchen wants to merge 6 commits into
mainfrom
pr-8170-xplat-ci

Conversation

@danielhanchen

Copy link
Copy Markdown
Collaborator

Disposable CI run for unslothai/unsloth#8170. Do not merge; closed after CI.

danielhanchen and others added 6 commits August 8, 2026 11:51
A Windows user could not update Studio until they killed a stray python by hand:
the tool sandbox runs its payload under a shell wrapper, the kill path reaped
only the wrapper, and `unsloth studio update` then refused to run because a
process still held the managed environment.

- taskkill /T on Windows, so a tool payload cannot outlive its wrapper
- a console-close handler, since CTRL_CLOSE_EVENT never becomes a Python signal
  and the graceful shutdown was skipped entirely when the window was closed
- the desktop updater drains the app job before standing down crash cleanup, and
  re-arms it when the install never happens
- children are recorded on disk and swept at the next startup, which is the only
  reaper macOS has after a crash or a force quit
- the job status is logged instead of failing silently

Also fixes a liveness probe that used os.kill(pid, 0); on Windows that is
TerminateProcess, so it killed the process it was asking about.
…d per owner, drop the job drain

- the console handler ran _signal_handler on the thread Windows creates for the
  event, where signal.signal raises, so closing the window did no cleanup at all
- bound that work to the ~5s Windows allows before it kills the process
- one record file per owner pid: two Studios can share a home, and a single file
  let the second erase the first's children
- add a Windows process identity (creation time) and refuse to signal a pid that
  cannot be verified
- drop the whole-job drain: it would also terminate the WebView2 hosts, and
  cleanup_child_processes already taskkills the backend tree
A record that is not an object, or whose children are not dicts, raised out of
the startup sweep and would have stopped Studio from starting. Pair the Linux
start time with the command name as well, since start time alone has 10ms
granularity.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d2b41006ad

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread studio/backend/run.py
# crashed left its sidecars running. Sweep before spawning anything: a
# leftover holds VRAM, a port, and the files an update has to replace.
try:
reaped = reap_recorded_children()

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Record tool subprocesses for the macOS startup sweep

When Studio is killed on macOS during a Python or shell tool call, the child continues running because _python_exec and _shell_exec spawn at tools.py:10332 and tools.py:10457 without calling adopt_pid. Consequently this sweep has no record of those processes and cannot reap them on the next launch; a sleeping or file-holding tool payload can therefore survive indefinitely despite the new abnormal-exit cleanup.

Useful? React with 👍 / 👎.

Comment on lines +496 to +498
tmp = path.with_suffix(".tmp")
tmp.write_text(json.dumps(payload), encoding = "utf-8")
tmp.replace(path)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Serialize breadcrumb snapshot writes

When two worker threads call adopt_pid or forget_pid concurrently, both writes use the same .tmp path without a lock. An older _tracked_pids snapshot can be written and replaced after the newer snapshot, or one replace can consume the other thread's temp file; the exception is then swallowed. On macOS this can omit a live child from the only crash-survivable record, so a subsequent startup will leave that child orphaned.

Useful? React with 👍 / 👎.

Comment thread studio/backend/run.py
Comment on lines +1182 to +1183
del CTRL_C_EVENT, CTRL_BREAK_EVENT
return False

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Return false for Ctrl events without deleting constants

On Windows, Ctrl+C and Ctrl+Break take this non-close branch, but del CTRL_C_EVENT, CTRL_BREAK_EVENT makes both names local to the callback and raises UnboundLocalError before return False. Because this runs through a ctypes console-control callback, the exception is reported/ignored at the callback boundary instead of intentionally passing the event onward to Python's signal handler, making Ctrl-event handling unreliable.

Useful? React with 👍 / 👎.

@danielhanchen
danielhanchen deleted the pr-8170-xplat-ci branch August 8, 2026 13:23
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