mirror of
https://github.com/stablyai/orca.git
synced 2026-10-31 00:57:45 +00:00
fix(ssh): retry with the saved Node.js mirror once a running connect fails the same way (#31089)
* fix(ssh): retry with the saved mirror once a connect already dialing fails * fix(ssh): note why the status is current when the lock clears
This commit is contained in:
@@ -3,12 +3,25 @@ import {
|
||||
NODE_DIST_MIRROR_SUGGESTION,
|
||||
saveNodeDistMirrorAndRetry
|
||||
} from './node-dist-mirror-recovery'
|
||||
import type { SshManagedServerStatus } from '../../../shared/ssh-types'
|
||||
import { useAppStore } from '@/store'
|
||||
import {
|
||||
beginSshConnect,
|
||||
endSshConnect,
|
||||
isSshConnectInFlight,
|
||||
resetSshConnectInFlightForTests
|
||||
} from './ssh-connect-in-flight'
|
||||
|
||||
function setManagedServer(managedServer: SshManagedServerStatus): void {
|
||||
useAppStore.getState().setSshConnectionState('ssh-1', {
|
||||
targetId: 'ssh-1',
|
||||
status: managedServer.kind === 'managed' ? 'connected' : 'error',
|
||||
error: null,
|
||||
reconnectAttempt: 0,
|
||||
managedServer
|
||||
})
|
||||
}
|
||||
|
||||
function deps() {
|
||||
const calls: string[] = []
|
||||
let finishConnect: () => void = () => {}
|
||||
@@ -27,7 +40,10 @@ function deps() {
|
||||
}
|
||||
}
|
||||
|
||||
afterEach(() => resetSshConnectInFlightForTests())
|
||||
afterEach(() => {
|
||||
resetSshConnectInFlightForTests()
|
||||
useAppStore.getState().clearRemovedSshTargetState('ssh-1')
|
||||
})
|
||||
|
||||
describe('save a Node.js mirror and retry', () => {
|
||||
it('saves the normalized mirror first, then retries the connect as an in-flight attempt', async () => {
|
||||
@@ -62,12 +78,34 @@ describe('save a Node.js mirror and retry', () => {
|
||||
expect(d.connect).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('saves but leaves a connect already dialing to finish on its own', async () => {
|
||||
it('retries with the new mirror once a connect already dialing fails the same way', async () => {
|
||||
const d = deps()
|
||||
beginSshConnect('ssh-1')
|
||||
const result = await saveNodeDistMirrorAndRetry('ssh-1', 'https://mirror.example/node', d)
|
||||
expect(result.outcome).toBe('retrying')
|
||||
expect(d.save).toHaveBeenCalled()
|
||||
expect(d.calls).toEqual(['save https://mirror.example/node'])
|
||||
|
||||
// The dialing connect misses the mirror and fails with the same blocked download.
|
||||
setManagedServer({
|
||||
kind: 'relay',
|
||||
reason: 'failed',
|
||||
nodeDownloadBlocked: { mirror: 'unset' }
|
||||
})
|
||||
endSshConnect('ssh-1')
|
||||
await vi.waitFor(() => expect(d.connect).toHaveBeenCalledWith('ssh-1'))
|
||||
expect(d.calls).toEqual(['save https://mirror.example/node', 'connect ssh-1'])
|
||||
expect(isSshConnectInFlight('ssh-1')).toBe(true)
|
||||
})
|
||||
|
||||
it('does not reconnect when the connect already dialing succeeded', async () => {
|
||||
const d = deps()
|
||||
beginSshConnect('ssh-1')
|
||||
const result = await saveNodeDistMirrorAndRetry('ssh-1', 'https://mirror.example/node', d)
|
||||
setManagedServer({ kind: 'managed', environmentId: 'env-1' })
|
||||
endSshConnect('ssh-1')
|
||||
if (result.outcome === 'retrying') {
|
||||
await result.retry
|
||||
}
|
||||
expect(d.connect).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
|
||||
@@ -7,8 +7,16 @@ import type { SshManagedServerStatus } from '../../../shared/ssh-types'
|
||||
import { translate } from '@/i18n/i18n'
|
||||
import { isPairedWebClientWindow } from '@/lib/desktop-window-chrome'
|
||||
import { useAppStore } from '@/store'
|
||||
import { isSshConnectInFlight, trackSshConnect } from './ssh-connect-in-flight'
|
||||
import { nodeMirrorRecovery, type NodeMirrorRecovery } from './ssh-host-node-download-copy'
|
||||
import {
|
||||
isSshConnectInFlight,
|
||||
subscribeSshConnectInFlight,
|
||||
trackSshConnect
|
||||
} from './ssh-connect-in-flight'
|
||||
import {
|
||||
blockedNodeDownload,
|
||||
nodeMirrorRecovery,
|
||||
type NodeMirrorRecovery
|
||||
} from './ssh-host-node-download-copy'
|
||||
|
||||
export const NODE_DIST_MIRROR_SUGGESTION = 'https://npmmirror.com/mirrors/node/'
|
||||
|
||||
@@ -107,9 +115,27 @@ export async function saveNodeDistMirrorAndRetry(
|
||||
)
|
||||
}
|
||||
}
|
||||
// Why: a connect already dialing keeps its own attempt; a second one would race it.
|
||||
if (isSshConnectInFlight(targetId)) {
|
||||
return { outcome: 'retrying', retry: Promise.resolve() }
|
||||
if (!isSshConnectInFlight(targetId)) {
|
||||
return { outcome: 'retrying', retry: trackSshConnect(targetId, deps.connect(targetId)) }
|
||||
}
|
||||
return { outcome: 'retrying', retry: trackSshConnect(targetId, deps.connect(targetId)) }
|
||||
// Why wait: a second connect would race the one dialing, which may be past the download already.
|
||||
// The status is current once the lock clears: main publishes a failed setup before it rejects.
|
||||
const retry = sshConnectSettled(targetId).then(() =>
|
||||
blockedNodeDownload(useAppStore.getState().sshConnectionStates.get(targetId)?.managedServer)
|
||||
? trackSshConnect(targetId, deps.connect(targetId))
|
||||
: undefined
|
||||
)
|
||||
return { outcome: 'retrying', retry }
|
||||
}
|
||||
|
||||
/** Resolves once no connect for `targetId` holds the shared in-flight lock. */
|
||||
function sshConnectSettled(targetId: string): Promise<void> {
|
||||
return new Promise((resolve) => {
|
||||
const unsubscribe = subscribeSshConnectInFlight(() => {
|
||||
if (!isSshConnectInFlight(targetId)) {
|
||||
unsubscribe()
|
||||
resolve()
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user