mirror of
https://github.com/stablyai/orca.git
synced 2026-09-22 00:02:31 +00:00
fix(settings): treat a host-too-old status read as an outdated server
This commit is contained in:
@@ -12,6 +12,7 @@ import {
|
||||
} from './runtime-environment-host-details'
|
||||
import { SessionHistoryComputerRow } from './SessionHistoryComputerRow'
|
||||
import {
|
||||
isHostTooOldError,
|
||||
sessionSearchCheckingMessage,
|
||||
sessionSearchReadErrorMessage,
|
||||
sessionSearchStatusDetails,
|
||||
@@ -19,11 +20,6 @@ import {
|
||||
} from './session-history-status-copy'
|
||||
import { useSessionSearchStatus } from './use-session-search-status'
|
||||
|
||||
// IPC wraps a rejection's message, so the host-too-old marker arrives inside a longer string.
|
||||
function isHostTooOldError(error: unknown): boolean {
|
||||
return error instanceof Error && error.message.includes('host-too-old')
|
||||
}
|
||||
|
||||
export function SessionHistoryServerRow({
|
||||
environment,
|
||||
details,
|
||||
@@ -38,14 +34,16 @@ export function SessionHistoryServerRow({
|
||||
const mounted = useMountedRef()
|
||||
const openSettingsPage = useAppStore((state) => state.openSettingsPage)
|
||||
const openSettingsTarget = useAppStore((state) => state.openSettingsTarget)
|
||||
const [tooOld, setTooOld] = useState(false)
|
||||
const [tooOldOnSet, setTooOldOnSet] = useState(false)
|
||||
const [busy, setBusy] = useState(false)
|
||||
const connectionState = getRuntimeServerConnectionState(details)
|
||||
const connected = isRuntimeServerTransportConnected(connectionState)
|
||||
const { status, failed, adopt } = useSessionSearchStatus({
|
||||
const { status, failed, hostTooOld, adopt } = useSessionSearchStatus({
|
||||
executionHostId: hostId,
|
||||
active: connected && !tooOld
|
||||
active: connected && !tooOldOnSet
|
||||
})
|
||||
// A status read or a set call can each prove the server predates session search.
|
||||
const tooOld = tooOldOnSet || hostTooOld
|
||||
const enabled = status?.enabled === true
|
||||
|
||||
async function setEnabled(next: boolean): Promise<void> {
|
||||
@@ -58,7 +56,7 @@ export function SessionHistoryServerRow({
|
||||
return
|
||||
}
|
||||
if (isHostTooOldError(error)) {
|
||||
setTooOld(true)
|
||||
setTooOldOnSet(true)
|
||||
return
|
||||
}
|
||||
onError(
|
||||
|
||||
@@ -94,3 +94,8 @@ export function sessionSearchOffMessage(): string {
|
||||
export function sessionSearchReadErrorMessage(): string {
|
||||
return translate('sessionHistory.status.error', 'Could not read index status. Retrying…')
|
||||
}
|
||||
|
||||
// IPC wraps a rejection's message, so the host-too-old marker arrives inside a longer string.
|
||||
export function isHostTooOldError(error: unknown): boolean {
|
||||
return error instanceof Error && error.message.includes('host-too-old')
|
||||
}
|
||||
|
||||
@@ -235,3 +235,18 @@ it('does not overlap slow status requests and stops polling on unmount', async (
|
||||
})
|
||||
expect(mocks.status).toHaveBeenCalledTimes(beforeUnmount)
|
||||
})
|
||||
|
||||
it('marks the host too old on a host-too-old rejection and stops polling', async () => {
|
||||
mocks.status.mockRejectedValue(new Error('Error invoking remote method: host-too-old'))
|
||||
const { result } = poll()
|
||||
await act(async () => {
|
||||
await vi.advanceTimersByTimeAsync(0)
|
||||
})
|
||||
expect(result.current.hostTooOld).toBe(true)
|
||||
expect(result.current.failed).toBe(true)
|
||||
const calls = mocks.status.mock.calls.length
|
||||
await act(async () => {
|
||||
await vi.advanceTimersByTimeAsync(30_000)
|
||||
})
|
||||
expect(mocks.status.mock.calls.length).toBe(calls)
|
||||
})
|
||||
|
||||
@@ -3,11 +3,13 @@ import type { AiVaultSearchStatus } from '../../../../shared/ai-vault-search-typ
|
||||
import type { ExecutionHostId } from '../../../../shared/execution-host'
|
||||
import { useWindowStreamVisible } from '@/hooks/use-window-stream-visibility'
|
||||
import { installWindowVisibilityInterval } from '@/lib/window-visibility-interval'
|
||||
import { sessionSearchPollIntervalMs } from './session-history-status-copy'
|
||||
import { isHostTooOldError, sessionSearchPollIntervalMs } from './session-history-status-copy'
|
||||
|
||||
export type SessionSearchStatusRead = {
|
||||
status: AiVaultSearchStatus | null
|
||||
failed: boolean
|
||||
/** The host answered that it has no session search at all; polling stops. */
|
||||
hostTooOld: boolean
|
||||
/** Adopt a status the caller already holds, e.g. the answer to a set call. */
|
||||
adopt: (status: AiVaultSearchStatus) => void
|
||||
}
|
||||
@@ -27,6 +29,7 @@ export function useSessionSearchStatus(args: {
|
||||
const visible = useWindowStreamVisible(0)
|
||||
const [status, setStatus] = useState<AiVaultSearchStatus | null>(null)
|
||||
const [failed, setFailed] = useState(false)
|
||||
const [hostTooOld, setHostTooOld] = useState(false)
|
||||
const intervalMs = sessionSearchPollIntervalMs(status)
|
||||
const adopt = useCallback((next: AiVaultSearchStatus) => {
|
||||
setStatus(next)
|
||||
@@ -38,7 +41,7 @@ export function useSessionSearchStatus(args: {
|
||||
setFailed(false)
|
||||
return
|
||||
}
|
||||
if (!visible) {
|
||||
if (!visible || hostTooOld) {
|
||||
return
|
||||
}
|
||||
let disposed = false
|
||||
@@ -56,10 +59,13 @@ export function useSessionSearchStatus(args: {
|
||||
setStatus(next)
|
||||
setFailed(false)
|
||||
}
|
||||
} catch {
|
||||
} catch (error) {
|
||||
if (!disposed) {
|
||||
setStatus(null)
|
||||
setFailed(true)
|
||||
if (isHostTooOldError(error)) {
|
||||
setHostTooOld(true)
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
inFlight = false
|
||||
@@ -70,7 +76,7 @@ export function useSessionSearchStatus(args: {
|
||||
disposed = true
|
||||
stopPolling()
|
||||
}
|
||||
}, [executionHostId, active, visible, refresh, intervalMs])
|
||||
}, [executionHostId, active, visible, refresh, intervalMs, hostTooOld])
|
||||
|
||||
return { status, failed, adopt }
|
||||
return { status, failed, hostTooOld, adopt }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user