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:
@@ -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', () => {
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user