mirror of
https://github.com/stablyai/orca.git
synced 2026-10-04 08:02:09 +00:00
fix(cli): stop reporting a recovered runtime as unreachable
The open-window poll carried the earlier reason forward with `?? lastReason`, so a runtime that came back mid-wait still timed out with "its runtime is unreachable" and a reason naming a socket it no longer uses -- a stale negative reported as the current diagnosis. Clear the reason whenever the status says reachable. That leaves two genuinely different timeouts, so give them different words: one never got an answer; the other answered the whole time and opened no window, where "may still be running headlessly" understates what the poll already proved.
This commit is contained in:
committed by
Merge Sim
parent
70dc4e28fd
commit
a90ce02e08
@@ -348,6 +348,56 @@ describe.skipIf(process.platform === 'win32')('RuntimeClient', () => {
|
||||
})
|
||||
})
|
||||
|
||||
// STA-3969: the poll carried the earlier reason forward with `?? lastReason`, so a runtime
|
||||
// that RECOVERED mid-wait was still reported unreachable at the timeout -- a stale negative
|
||||
// presented as the current diagnosis.
|
||||
it('openOrca stops reporting a runtime unreachable once it answers again', async () => {
|
||||
const userDataPath = mkdtempSync(join(tmpdir(), 'orca-runtime-client-'))
|
||||
const endpoint = join(userDataPath, 'runtime.sock')
|
||||
const server = createServer((socket) => {
|
||||
sockets.add(socket)
|
||||
socket.once('close', () => sockets.delete(socket))
|
||||
socket.once('data', (data) => {
|
||||
const request = JSON.parse(String(data).trim()) as { id: string }
|
||||
socket.write(
|
||||
`${JSON.stringify({
|
||||
id: request.id,
|
||||
ok: true,
|
||||
result: {
|
||||
runtimeId: 'runtime-1',
|
||||
rendererGraphEpoch: 0,
|
||||
graphStatus: 'ready',
|
||||
authoritativeWindowId: 0,
|
||||
desktopWindowStatus: 'initializing',
|
||||
liveTabCount: 0,
|
||||
liveLeafCount: 0
|
||||
},
|
||||
_meta: { runtimeId: 'runtime-1' }
|
||||
})}\n`
|
||||
)
|
||||
})
|
||||
})
|
||||
servers.add(server)
|
||||
await new Promise<void>((resolve) => server.listen(endpoint, resolve))
|
||||
// Starts pointed at an endpoint nothing serves, then recovers onto the live one.
|
||||
writeMetadata(userDataPath, join(userDataPath, 'never-listened.sock'), 'token', process.pid)
|
||||
vi.mocked(launchOrcaApp).mockImplementationOnce(() => {
|
||||
writeMetadata(userDataPath, endpoint, 'token', process.pid)
|
||||
})
|
||||
|
||||
const client = new RuntimeClient(userDataPath, 100)
|
||||
|
||||
const failure = await client.openOrca(1_000).then(
|
||||
() => null,
|
||||
(error: unknown) => error as { code: string; message: string; data?: unknown }
|
||||
)
|
||||
expect(failure?.code).toBe('runtime_open_timeout')
|
||||
expect(failure?.message).not.toContain('unreachable')
|
||||
expect(failure?.data).toBeUndefined()
|
||||
// The second timeout case: answers all the way through, just no window.
|
||||
expect(failure?.message).toContain('is responding and still running headlessly')
|
||||
})
|
||||
|
||||
it('openOrca waits for a reachable headless runtime to expose a desktop window', async () => {
|
||||
const userDataPath = mkdtempSync(join(tmpdir(), 'orca-runtime-client-'))
|
||||
const endpoint = join(userDataPath, 'runtime.sock')
|
||||
|
||||
@@ -264,6 +264,7 @@ export class RuntimeClient {
|
||||
|
||||
const startedAt = Date.now()
|
||||
let lastReason = initial.result.runtime.unreachableReason
|
||||
let runtimeAnswered = initial.result.runtime.reachable
|
||||
while (Date.now() - startedAt < timeoutMs) {
|
||||
const status = await this.getCliStatus()
|
||||
if (status.result.app.desktopWindowStatus === 'blocked') {
|
||||
@@ -272,18 +273,30 @@ export class RuntimeClient {
|
||||
if (status.result.app.desktopWindowStatus === 'available') {
|
||||
return status
|
||||
}
|
||||
lastReason = status.result.runtime.unreachableReason ?? lastReason
|
||||
// Why (STA-3969): a runtime that answered is reachable NOW, so carrying the earlier
|
||||
// reason forward would report a stale negative -- naming an endpoint it no longer
|
||||
// uses -- as the current diagnosis.
|
||||
runtimeAnswered = status.result.runtime.reachable
|
||||
lastReason = runtimeAnswered
|
||||
? undefined
|
||||
: (status.result.runtime.unreachableReason ?? lastReason)
|
||||
await delay(250)
|
||||
}
|
||||
|
||||
// Why: STA-3969 — this loop polls getCliStatus, so when the runtime is
|
||||
// unreachable it burns the whole timeout and then reported only that it timed
|
||||
// out. Carry the reachability failure the poll already diagnosed.
|
||||
// Why: the two timeouts are different failures. One never got an answer from the
|
||||
// runtime; the other got answers the whole time and no window with them -- telling that
|
||||
// user the runtime "may" be running headlessly understates what the poll already proved.
|
||||
const timeoutDetail = lastReason
|
||||
? `: the Orca app process is running but its runtime is unreachable. ${lastReason.message}`
|
||||
: runtimeAnswered
|
||||
? '. The Orca runtime is responding and still running headlessly; it did not open a window in time.'
|
||||
: '. The runtime may still be running headlessly.'
|
||||
throw new RuntimeClientError(
|
||||
'runtime_open_timeout',
|
||||
lastReason
|
||||
? `Timed out waiting for an Orca desktop window: the Orca app process is running but its runtime is unreachable. ${lastReason.message}`
|
||||
: 'Timed out waiting for an Orca desktop window. The runtime may still be running headlessly.',
|
||||
`Timed out waiting for an Orca desktop window${timeoutDetail}`,
|
||||
lastReason ? { unreachableReason: lastReason } : undefined
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user