feat(connector): add Server Status editor window#30
Open
rkdrnf wants to merge 3 commits into
Open
Conversation
The listener could enter several dead states that required an Editor restart to recover from: 1. Zombie listener: Start() early-returned when s_Listener != null, so if the listener crashed without nulling the reference, every later call became a no-op. 2. ListenLoop exited via exception without clearing s_Listener, leaving the connector permanently dead until the next assembly reload. 3. Initial port-in-use was fatal — once all 10 ports failed at startup, nothing ever retried. 4. A hung command handler held CommandRouter's static semaphore forever; restarting the HTTP server didn't help because the lock lives in CommandRouter. Changes: - HttpServer.IsRunning checks the listener actually accepts traffic, and Start() tears down a stale reference before rebinding. - ListenLoop has a finally block that nulls the listener and marks the heartbeat stopped if it exits unexpectedly. - ProcessQueue acts as a watchdog: if the listener is down it calls Start() (rate-limited via AUTO_RESTART_INTERVAL), so transient port conflicts and silent crashes recover automatically. Failure logging is rate-limited to avoid console spam. - CommandRouter.Dispatch captures the semaphore locally so a ResetLock() swap can't make an in-flight call double-release the new semaphore. ResetLock() exposes a recovery hook for future UI/CLI surfaces that need to clear a hung handler without restarting Unity. - Heartbeat.MarkStopped() lets failure paths flag the heartbeat file as dead so the CLI sees an honest "not responding" state.
MarkStopped() set s_ForcedState = "stopped" and wrote, but the next Tick (~500ms later) cleared s_ForcedState and wrote a live snapshot because Tick only guarded on Port == 0 — a port set during the last successful bind survives a listener crash. Result: the "stopped" state existed for one heartbeat interval, then got overwritten with state="ready" while the listener was actually dead. Switch the guard to !HttpServer.IsRunning so the heartbeat goes silent when the listener is down, letting MarkStopped's write persist until the watchdog restarts it.
Adds a Tools > Unity CLI > Server Status window that shows the
connector's runtime state and exposes recovery levers for the
failure scenarios fixed in the prior commit:
- Status dot, port, current Heartbeat state.
- Queued command count and pending-test list (read from existing
test-pending-{port}.json files).
- Start / Stop / Restart buttons. ManualStop sets s_ManuallyStopped
so the watchdog respects the user's intent (otherwise the watchdog
would instantly revive the listener).
- Purge button — drains the queue, faults every in-flight
TaskCompletionSource with "Purged by user", calls
CommandRouter.ResetLock(), and deletes test-pending-*.json files.
Confirmation dialog gates the action since it's destructive for
any waiting CLI client.
HttpServer now tracks pending TCS in a ConcurrentDictionary so
PurgePending can fault them. ProcessItem switches to TrySetResult
so the racing PurgePending call doesn't double-set.
Heartbeat exposes CurrentState for the window's display row;
returns "stopped" when the listener is down so the dot and label
stay consistent with reality after ManualStop.
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.
Summary
Adds a
Tools > Unity CLI > Server Statuseditor window that showsthe connector's runtime state and exposes recovery levers for the
failure scenarios fixed in #29.
What it adds
Editor window
Heartbeatstatetest-pending-{port}.jsonfiles written byTestRunnerState)HttpServer.ManualStart/ManualStopAPIs.ManualStopsetss_ManuallyStoppedso the failure-recovery watchdog respects theuser's intent (otherwise it would instantly revive the listener
and the Stop button would be useless)
TaskCompletionSourcewith"Purged by user", and callsCommandRouter.ResetLock()(the recovery hook exposed in fix(connector): auto-recover when HTTP listener dies #29).Gated by
EditorUtility.DisplayDialogsince it's destructive forany waiting CLI client
New connector APIs
HttpServer.PendingCount,HttpServer.PurgePending(),HttpServer.ManualStart/ManualStopHeartbeat.CurrentState— returns\"stopped\"when the listeneris down so the window stays truthful after
ManualStopImplementation notes
s_Pending(ConcurrentDictionary) tracks in-flight TCS; populatedin
HandleRequestenqueue, drained inProcessItemfinally andPurgePendingProcessItemswitches toTrySetResultso a racingPurgePendingdoesn't trigger a double-set exception
Test plan
Tools > Unity CLI > Server Status. With Unity idle:Status = Running, Port shown, State =
ready, Queued = 0.stopped. Watchdogdoes not revive (verify by waiting >5s and checking logs).
verify Queued count > 0 and the pending test row shows port +
filter.
\"Purged by user\"and Queued returns to 0.restarts (Stop intent should not survive a domain reload).
go test ./...passes (no Go-side changes).