fix(desktop): dispatch probe falls back to /api/status on pre-/api/health remotes

Switching the pooled dispatch probe to /api/health (salvaged from #97914)
would 404 on every dispatch against a remote older than 0.19, retire the
tunnel and reconnect forever - the same storm #107997 describes, moved to
old backends. Fall back to /api/status on an explicit 404 exactly the way
the boot readiness probe already does (backend-health.ts). The legacy
fallback idea and its test are taken from #101976 (@edosulai); the rest of
that PR (timeout-tolerance streak, ServerAlive SSH options) is not adopted.

Co-authored-by: Edo Sulaiman <edosulai@icloud.com>
This commit is contained in:
Teknium
2026-09-11 02:56:15 -07:00
parent ee8257d601
commit d1bd7b00df
2 changed files with 48 additions and 3 deletions

View File

@@ -329,6 +329,36 @@ describe('ensureHealthyPooledRemoteBackendForDispatch', () => {
expect(retire).toHaveBeenCalledOnce()
expect(reconnect).toHaveBeenCalledOnce()
})
it('falls back to /api/status when /api/health returns 404 on older backends', async () => {
const legacy = { baseUrl: 'http://127.0.0.1:49525', mode: 'remote' }
const legacyPromise = Promise.resolve(legacy)
const retire = vi.fn()
const reconnect = vi.fn()
const probe = vi.fn(async (_connection, path) => {
if (path === '/api/health') {
throw new Error('404: Not Found')
}
})
await expect(
ensureHealthyPooledRemoteBackendForDispatch({
connectionPromise: legacyPromise,
currentConnectionPromise: () => legacyPromise,
probe,
reconnect,
retire
})
).resolves.toBe(legacy)
expect(probe).toHaveBeenCalledWith(legacy, '/api/status', {
timeoutMs: POOLED_REMOTE_DISPATCH_PROBE_TIMEOUT_MS
})
expect(retire).not.toHaveBeenCalled()
expect(reconnect).not.toHaveBeenCalled()
})
})
describe('revalidatePooledRemoteBackends', () => {

View File

@@ -1,3 +1,5 @@
import { isMissingHealthEndpointError } from './backend-health'
export const REMOTE_LIVENESS_TIMEOUT_MS = 10_000
// Dispatch is synchronous user intent: a cached descriptor must prove its
// forwarded endpoint is alive before it can be returned. Probe cheap
@@ -102,9 +104,22 @@ export async function ensureHealthyPooledRemoteBackendForDispatch<TConnection ex
return reconnect()
}
await probe(connection, '/api/health', {
timeoutMs: POOLED_REMOTE_DISPATCH_PROBE_TIMEOUT_MS
})
try {
await probe(connection, '/api/health', {
timeoutMs: POOLED_REMOTE_DISPATCH_PROBE_TIMEOUT_MS
})
} catch (healthError) {
// A remote that predates /api/health would otherwise 404 every dispatch,
// retire the tunnel and reconnect forever; the boot probe falls back the
// same way (backend-health.ts).
if (!isMissingHealthEndpointError(healthError)) {
throw healthError
}
await probe(connection, '/api/status', {
timeoutMs: POOLED_REMOTE_DISPATCH_PROBE_TIMEOUT_MS
})
}
} catch (error) {
if (currentConnectionPromise() === connectionPromise) {
await retire(error)