Repository navigation
fix(watchdog): detect and restart wedged M2 workers, not just the orchestrator - #45
Merged
Merged
Conversation
…hestrator Yesterday's fix covered the orchestrator. Overnight the same mlx crash took out both M2 workers and nothing noticed. developer crashed at 22:03 and reviewer at 22:53 on 2026-08-24, both with `[metal::malloc] Resource limit (499000) exceeded` killing the generation thread. From then until 05:10 every OpenCode request to either endpoint timed out at the meter's 300s header deadline -- 126 failures, zero successes in seven hours. Nothing recovered them because this watchdog only ever looked at the M1 orchestrator, and every check it did run kept passing: the machine was up, the Thunderbolt link was fine, memory was 98% free, and both servers answered /v1/models with 200 the whole time. Detection is drawn from the meter's telemetry rather than another log grep across the link, which would mean an ssh on every tick. The meter already records every client request, so an upstream carrying 3+ chat failures and ZERO successes over 15 minutes is wedged by definition. Restricted to kind='chat' because only a real completion proves the generation thread is alive. Failures alongside successes are ordinary life on a busy server and are left alone; so is silence, since no traffic is not evidence of a wedge. Only the restart crosses to M2, and it needs no sudo: the workers are LaunchDaemons with KeepAlive SuccessfulExit=false, so killing the process makes launchd load a fresh one. The kill pattern is `mlx_lm[.]server` rather than `mlx_lm.server` so it cannot match the remote shell running pkill, which carries the pattern text in its own command line. The check runs only inside the M2-reachable branch. When the link is down every request fails too, and that is the reachability path below, not a wedge. Both workers were restarted by hand at 05:1x and are serving again; verified through the meter on :9002 and :9003. Dry-run against the live stack correctly found nothing to do, since both now show successes in the window. Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
This was referenced Aug 25, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What happened
Yesterday's #44 covered the orchestrator. Overnight the same mlx crash took out both M2 workers and nothing noticed.
developercrashed at 22:03,reviewerat 22:53 on 2026-08-24[metal::malloc] Resource limit (499000) exceededkilling the generation threadEvery check the watchdog already ran kept passing. The machine was up, the Thunderbolt link was fine, memory was 98% free with no swap, and both servers answered
/v1/modelswith 200 the whole time./v1/modelsproves the process is alive, not that it can generate.Detection
From the meter's telemetry, not another log grep — reading M2's logs would mean an ssh on every tick. The meter already records every client request, so an upstream carrying 3+ chat failures and zero successes over 15 minutes is wedged by definition.
Restricted to
kind='chat', because only a real completion proves the generation thread is alive.Deliberately left alone:
Restart
No sudo needed. The workers are LaunchDaemons with
KeepAlive SuccessfulExit=falserunning asadmin, so killing the process makes launchd load a fresh one.The pattern is
mlx_lm[.]server, notmlx_lm.server:pkill -fmatches full command lines, and the remote shell running thepkillcarries the pattern text in its own. Without the bracket it can kill its own session.Verification
:9002and:9003.Coverage after this
launchctl kickstartssh m2 pkill→ launchdKeepAliveDocs updated in
TROUBLESHOOTING.md(the crash affects every mlx endpoint, with the M2 restart command),OPERATIONS.md(a table of what the watchdog covers and how), andMODELS.md(the known-failure note now says every endpoint, not just the orchestrator).🤖 Generated with Claude Code