fix(vscode): adopt a same-key pending lint runtime instead of restarting it - #35
Merged
Merged
Conversation
…ing it At activation the register-time reconcile, a detection pass and didOpen routinely land inside one lint worker startup window. reconcile() swept the document's pending runtime uses before knowing what the new pass would resolve to, so the second reconcile tore down the not-yet-bound runtime mid-LSP-initialize (SIGTERM), vscode-languageclient force-notified "Server initialization failed" / "couldn't create connection to server", and an identical runtime was then started from scratch. - RuntimeManager.reconcile now resolves the document's core first (planDocumentCore) and the pending-use sweep keeps a pending entry whose key matches the plan — the reconcile adopts the in-flight start. A key change still cancels the pending start immediately, and a superseded operation leaves the entry's fate to the newest reconcile's sweep. - Rslint.close() gives a still-Starting client one bounded chance (2s) to settle before tearing down the transport, so legitimate mid-start closes (document closed during start, core key changed) stop cleanly instead of triggering the same forced toasts; planned aborts are no longer logged as errors. The pre-teardown wait subsumes the old post-dispose start wait. Both are ahead-of-upstream fixes, recorded in AGENTS.md to be offered back on the next sync. Regression-locked in tests/stacks/lint/runtimeManager.test.ts.
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
Fixes a startup teardown race reported from a real user log: at activation, the first lint worker was SIGTERMed ~1.1s after spawn — while the LSP
initializewas still in flight — then an identical runtime (same core, same shim, same runtime key) started successfully right after. vscode-languageclient force-notifies "Server initialization failed" / "couldn't create connection to server" when its in-flightinitializeis severed (verified against vscode-languageclient 9.0.1; those toasts cannot be suppressed via client options), so users saw scary error popups for what was a self-healing restart.Root cause:
RuntimeManager.reconcile()swept the document's pending runtime uses before resolving what the new pass would land on. The register-time reconcile, a detection pass anddidOpenroutinely land inside one worker startup window, so the second reconcile dropped the not-yet-bound entry's refcount to zero and tore the runtime down mid-initialize, even though it then resolved to the very same key.Fix (both ahead-of-upstream, recorded in AGENTS.md to offer back on the next sync):
RuntimeManager.reconcilenow resolves the document's core first (planDocumentCore); the pending-use sweep keeps a pending entry whose key matches the plan, adopting the in-flight start instead of restarting it. A key change still cancels the pending start immediately (a hung start cannot block the per-document tail), and a superseded operation leaves the entry's fate to the newest reconcile's sweep.Rslint.close()gives a still-Startingclient one bounded chance (2s, sharedCLOSE_SETTLEMENT_TIMEOUT_MS) to settle before tearing down the transport, covering the legitimate mid-start closes (document closed during start, core key changed). The pre-teardown wait subsumes the old post-dispose start wait, so a hung start pays the bound once. Planned aborts (close/supersede) are no longer logged as errors.Verification: new regression suite
tests/stacks/lint/runtimeManager.test.ts(same-key adoption — red before the fix; changed-key immediate cancel; document-close release),pnpm lint(type-checked) clean, full unit suite green, lint E2E slice (13 suites) all passing.Related Links
RuntimeManager(web-infra-dev/rslintpackages/vscode-extension) carries the same sweep ordering; both fixes are candidates to send upstream on the next sync.Checklist