perf(wsl): hold the distro alongside the read-only context probes (#35037)

* perf(wsl): hold the distro alongside the read-only context probes

The kernel probe has already started the distro, so the holder now runs alongside the four
read-only context reads instead of before them; it is still held before recovery, which may
launch orcad. No new wsl.exe spawns. The WSL 1 check and the parallel hold move to
wsl-orcad-held-context.ts.

# Conflicts:
#	src/main/wsl/wsl-orcad-deploy.ts

* fix(wsl): stop the context probes once the distro hold fails

A failed hold left the context probes running; after the deploy disposes its transport they fall
back to fresh wsl.exe execs, which could boot a distro that just went away (E9). The probes now
run under a child signal of the connect's, aborted on a hold failure or any other rejection.

* test(wsl): cover the context probes running while the hold is pending

Moves the ordering check out of the deploy suite, which is at its line cap after main's new
refusal tests, into the held-context suite.
This commit is contained in:
Neil
2026-10-28 04:53:32 -07:00
committed by GitHub
parent 15fac13c5f
commit ce3c8d1383
4 changed files with 203 additions and 24 deletions
+1 -11
View File
@@ -69,7 +69,7 @@ vi.mock('../managed-server/lifecycle/orcad-managed-runtime-context', async (impo
probeManagedOrcadReadiness: mocks.probe
}))
import { deployAndLaunchWslOrcad, isWsl1KernelRelease } from './wsl-orcad-deploy'
import { deployAndLaunchWslOrcad } from './wsl-orcad-deploy'
import { resetOrcadUpdateFailuresForTests } from '../managed-server/lifecycle/orcad-managed-update-failure-memory'
beforeEach(() => resetOrcadUpdateFailuresForTests())
@@ -837,13 +837,3 @@ describe('deployAndLaunchWslOrcad across an app update (E1)', () => {
expect(mocks.deploy.mock.calls[0][0].census.liveSessions).toBeNull()
})
})
describe('isWsl1KernelRelease', () => {
it('tells the WSL 1 syscall layer from a WSL 2 kernel, stock or custom', () => {
expect(isWsl1KernelRelease('4.4.0-19041-Microsoft')).toBe(true)
expect(isWsl1KernelRelease('4.4.0-22621-Microsoft\n')).toBe(true)
expect(isWsl1KernelRelease('5.15.167.4-microsoft-standard-WSL2')).toBe(false)
expect(isWsl1KernelRelease('6.6.36.6-microsoft-standard-WSL2+')).toBe(false)
expect(isWsl1KernelRelease('6.10.0-custom')).toBe(false)
})
})
+4 -13
View File
@@ -27,7 +27,6 @@ import { pruneWslOrcadVersionsUntilClean } from './wsl-orcad-version-gc-memo'
import { wakeAlreadyActiveOrcad } from '../ssh/orcad-already-active-wake'
import { OrcadActiveReadinessError } from '../ssh/orcad-active-readiness'
import { WslDistroNotRunningError } from './wsl-orcad-connection-errors'
import { resolveOrcadRemoteContext } from '../managed-server/install/orcad-remote-context'
import { deployOrcad } from '../ssh/orcad-remote-deploy'
import { isWslMoveUnderwayOnHost } from '../persistence/moving-wsl-projects/wsl-move-running-moves'
import { ORCAD_PID_FILENAME } from '../managed-server/install/orcad-remote-host-support'
@@ -37,10 +36,10 @@ import { joinRemotePath } from '../ssh/ssh-remote-platform'
import { readLocalFullVersion } from '../managed-server/install/remote-versioned-install'
import { createWslDistroHolder, type WslDistroHolder } from './wsl-distro-holder'
import { wslDistroHolderKey } from './wsl-distro-holder-record'
import { refuseMissingWslDistro, WslDistroVersion1Error } from './wsl-distro-unsupported'
import { readWslDistroRegistryIdShared } from './wsl-distro-registry-id'
import type { WslOrcadHostTarget } from './wsl-orcad-host-target'
import { createWslOrcadHostTransport, type WslOrcadHostTransport } from './wsl-orcad-host-transport'
import { holdWslDistroWithContext } from './wsl-orcad-held-context'
import { readWslOrcadIncumbent, type WslOrcadIncumbent } from './wsl-orcad-incumbent'
import { adoptUnrecordedWslOrcad } from './wsl-orcad-instance-adoption'
import {
@@ -98,11 +97,6 @@ export function defaultWslOrcadEnvironmentId(distro: string): string {
return `wsl:${wslDistroHolderKey(distro)}`
}
/** WSL 1 runs no Linux kernel, so the pinned Node and its pty cannot run there. */
export function isWsl1KernelRelease(release: string): boolean {
return /^\d+\.\d+\.\d+-\d+-Microsoft$/.test(release.trim())
}
export async function deployAndLaunchWslOrcad(
distro: string,
options: WslOrcadDeployOptions = {}
@@ -134,16 +128,13 @@ async function launchOverTransport(
const { signal } = options
let ownBuildVersion: string | null = null
const conn = withOwnBuildLaunchEnv(transport, () => ownBuildVersion)
const kernel = await execCommand(conn, 'uname -r', { signal }).catch(refuseMissingWslDistro(name))
if (isWsl1KernelRelease(kernel)) {
throw new WslDistroVersion1Error(name)
}
// Acquire a holder before launch or WSL can idle-stop orcad's distro.
const holder = options.holder ?? createWslDistroHolder({ userDataPath: userDataPath() })
const held = await holder.ensureHeld(name)
// Read GUID alongside deploy; failure leaves the record without one.
const distroId = (options.readRegistryId ?? readWslDistroRegistryIdShared)(name).catch(() => null)
let context = await resolveOrcadRemoteContext(target, conn, signal)
const first = await holdWslDistroWithContext(name, target, conn, holder, signal)
const held = first.held
let context = first.context
const slot = managedOrcadSlot(context, ORCAD_MANAGED_REMOTE_PORT, signal)
const recovery = await recoverInterruptedOrcadActivation(slot)
if (recovery.outcome === 'pending' || recovery.outcome === 'refused') {
+146
View File
@@ -0,0 +1,146 @@
import { beforeEach, describe, expect, it, vi } from 'vitest'
import type { OrcadHostTransport } from '../ssh/orcad-host-transport'
import type { WslDistroHolder } from './wsl-distro-holder'
import type { WslOrcadHostTarget } from './wsl-orcad-host-target'
const mocks = vi.hoisted(() => {
const state: { spawned: string[]; refused: string[]; probeStep: (() => void) | null } = {
spawned: [],
refused: [],
probeStep: null
}
return state
})
// Like the real execCommand: an aborted signal refuses before anything is spawned.
vi.mock('../ssh/remote-exec/remote-exec-command', () => ({
execCommand: vi.fn(
async (_conn: unknown, command: string, options?: { signal?: AbortSignal }) => {
if (options?.signal?.aborted) {
mocks.refused.push(command)
throw options.signal.reason
}
mocks.spawned.push(command)
return command === 'uname -r' ? '5.15.167.4-microsoft-standard-WSL2\n' : ''
}
)
}))
// Like the real context resolver: several probes in series, each passed the caller's signal.
vi.mock('../managed-server/install/orcad-remote-context', async () => {
const { execCommand } = await import('../ssh/remote-exec/remote-exec-command')
return {
resolveOrcadRemoteContext: async (
_target: unknown,
conn: OrcadHostTransport,
signal?: AbortSignal
) => {
for (const command of ['uname -sm', 'echo $HOME', 'ldd --version']) {
await new Promise<void>((resolve) => {
mocks.probeStep = resolve
})
await execCommand(conn, command, { signal })
}
return { remoteHome: '/home/u' }
}
}
})
import { holdWslDistroWithContext, isWsl1KernelRelease } from './wsl-orcad-held-context'
const target: WslOrcadHostTarget = { kind: 'wsl', id: 'wsl:u', distro: 'U', label: 'U' }
// oxlint-disable-next-line typescript/consistent-type-assertions -- SAFETY: every host call is mocked at its module.
const conn = {} as OrcadHostTransport
function holderRejectingOn(gate: Promise<void>): WslDistroHolder {
return {
ensureHeld: vi.fn(async () => {
await gate
throw new Error('holder exited before the distro started')
}),
adoptHolders: vi.fn(),
release: vi.fn(),
releaseAll: vi.fn(),
holderState: vi.fn()
}
}
beforeEach(() => {
mocks.spawned.length = 0
mocks.refused.length = 0
mocks.probeStep = null
})
describe('holdWslDistroWithContext', () => {
it('probes the context while the hold is pending, and resolves only once the distro is held', async () => {
let finishHold: () => void = () => {}
const holdDone = new Promise<void>((resolve) => {
finishHold = resolve
})
const hold: WslDistroHolder = {
...holderRejectingOn(holdDone),
ensureHeld: vi.fn(async (distro: string) => {
await holdDone
return {
outcome: 'spawned' as const,
record: { version: 1 as const, distro, pid: 9, creationTimeMs: 1, startedAtMs: 1 }
}
})
}
let settled = false
const held = holdWslDistroWithContext('U', target, conn, hold, undefined).finally(() => {
settled = true
})
for (let step = 0; step < 3; step++) {
await vi.waitFor(() => expect(mocks.probeStep).not.toBeNull())
const next = mocks.probeStep
mocks.probeStep = null
next?.()
}
await vi.waitFor(() =>
expect(mocks.spawned).toEqual(['uname -r', 'uname -sm', 'echo $HOME', 'ldd --version'])
)
// The deploy awaits this before recovery, which may launch orcad.
expect(settled).toBe(false)
finishHold()
await expect(held).resolves.toMatchObject({
held: { outcome: 'spawned' },
context: { remoteHome: '/home/u' }
})
})
it('stops the context probes once the hold fails, so nothing can boot the distro again', async () => {
let failHold: () => void = () => {}
const holdFails = new Promise<void>((resolve) => {
failHold = resolve
})
const held = holdWslDistroWithContext(
'U',
target,
conn,
holderRejectingOn(holdFails),
undefined
)
await vi.waitFor(() => expect(mocks.probeStep).not.toBeNull())
mocks.probeStep?.()
await vi.waitFor(() => expect(mocks.spawned).toEqual(['uname -r', 'uname -sm']))
failHold()
await expect(held).rejects.toThrow('holder exited')
mocks.probeStep?.()
await vi.waitFor(() => expect(mocks.refused).toEqual(['echo $HOME']))
expect(mocks.spawned).toEqual(['uname -r', 'uname -sm'])
})
})
describe('isWsl1KernelRelease', () => {
it('tells the WSL 1 syscall layer from a WSL 2 kernel, stock or custom', () => {
expect(isWsl1KernelRelease('4.4.0-19041-Microsoft')).toBe(true)
expect(isWsl1KernelRelease('4.4.0-22621-Microsoft\n')).toBe(true)
expect(isWsl1KernelRelease('5.15.167.4-microsoft-standard-WSL2')).toBe(false)
expect(isWsl1KernelRelease('6.6.36.6-microsoft-standard-WSL2+')).toBe(false)
expect(isWsl1KernelRelease('6.10.0-custom')).toBe(false)
})
})
+52
View File
@@ -0,0 +1,52 @@
import { resolveOrcadRemoteContext } from '../managed-server/install/orcad-remote-context'
import type { OrcadHostTransport } from '../ssh/orcad-host-transport'
import { execCommand } from '../ssh/remote-exec/remote-exec-command'
import type { WslDistroHolder } from './wsl-distro-holder'
import { refuseMissingWslDistro, WslDistroVersion1Error } from './wsl-distro-unsupported'
import type { WslOrcadHostTarget } from './wsl-orcad-host-target'
/** WSL 1 runs no Linux kernel, so the pinned Node and its pty cannot run there. */
export function isWsl1KernelRelease(release: string): boolean {
return /^\d+\.\d+\.\d+-\d+-Microsoft$/.test(release.trim())
}
/**
* Refuses WSL 1, then acquires the holder alongside the read-only context probes: the kernel probe
* already started the distro, so the holder spawns nothing extra, and it is held before the caller
* may launch orcad (recovery included) or WSL could idle-stop its distro.
*/
export async function holdWslDistroWithContext(
name: string,
target: WslOrcadHostTarget,
conn: OrcadHostTransport,
holder: WslDistroHolder,
signal: AbortSignal | undefined
) {
const kernel = await execCommand(conn, 'uname -r', { signal }).catch(refuseMissingWslDistro(name))
if (isWsl1KernelRelease(kernel)) {
throw new WslDistroVersion1Error(name)
}
// Once the hold fails, stop the probes: after dispose they fall back to fresh wsl.exe execs,
// which would boot a distro that just went away (E9).
const probes = new AbortController()
if (signal?.aborted) {
probes.abort(signal.reason)
}
const stopProbes = (): void => probes.abort(signal?.reason)
signal?.addEventListener('abort', stopProbes, { once: true })
try {
const [held, context] = await Promise.all([
holder.ensureHeld(name).catch((error: unknown) => {
probes.abort(error)
throw error
}),
resolveOrcadRemoteContext(target, conn, probes.signal)
])
return { held, context }
} catch (error) {
probes.abort(error)
throw error
} finally {
signal?.removeEventListener('abort', stopProbes)
}
}