mirror of
https://github.com/stablyai/orca.git
synced 2026-09-29 16:02:50 +00:00
fix(relay): check client abandonment between each accept lookup
CodeRabbit: a phone that hung up while resolveResume was in flight still paid for resolveInviteForMove and assignments.resolve. Check after each awaited lookup; regression test asserts neither later lookup runs.
This commit is contained in:
@@ -232,6 +232,43 @@ describe('client accept abandoned mid-DB-phase', () => {
|
||||
}
|
||||
})
|
||||
|
||||
it('stops after a slow resume lookup before starting the invite and assignment lookups', async () => {
|
||||
const h = harness()
|
||||
await activeHost(h)
|
||||
const store = h.store as typeof h.store & { resolveInviteForMove: ReturnType<typeof vi.fn> }
|
||||
store.resolveInviteForMove = vi.fn().mockResolvedValue(null)
|
||||
const slowResume = deferred<null>()
|
||||
h.store.resolveResume.mockReturnValueOnce(slowResume.promise)
|
||||
const resolveAssignment = (h.assignments as unknown as { resolve: ReturnType<typeof vi.fn> })
|
||||
.resolve
|
||||
resolveAssignment.mockClear()
|
||||
const client = new FakeSocket()
|
||||
const warn = vi.spyOn(console, 'warn').mockImplementation(() => undefined)
|
||||
try {
|
||||
const accepting = h.registry.acceptClient(
|
||||
client as unknown as WebSocket,
|
||||
identity.relayHostId,
|
||||
'credential'
|
||||
)
|
||||
await vi.advanceTimersByTimeAsync(0)
|
||||
client.close(1000, 'client bound')
|
||||
slowResume.resolve(null)
|
||||
await accepting
|
||||
|
||||
expect(store.resolveInviteForMove).not.toHaveBeenCalled()
|
||||
expect(resolveAssignment).not.toHaveBeenCalled()
|
||||
expect(h.store.reserveCredential).not.toHaveBeenCalled()
|
||||
expect(h.observer.recordClientAcceptAbandoned).toHaveBeenCalledWith(
|
||||
'assignment',
|
||||
expect.any(Number)
|
||||
)
|
||||
} finally {
|
||||
warn.mockRestore()
|
||||
h.registry.drain(0)
|
||||
vi.advanceTimersByTime(0)
|
||||
}
|
||||
})
|
||||
|
||||
it('still opens the connection when the phone is holding on', async () => {
|
||||
const h = harness()
|
||||
const control = await activeHost(h)
|
||||
|
||||
@@ -182,9 +182,14 @@ export class HostSessionRegistry {
|
||||
return true
|
||||
}
|
||||
if (this.config.role === 'cell') {
|
||||
const outerIdentity =
|
||||
(await this.store.resolveResume(hostId, credential)) ??
|
||||
(await this.store.resolveInviteForMove(hostId, credential))
|
||||
// Each lookup is its own pooled round trip; stop between them once the phone
|
||||
// has left instead of running the rest of the chain for nobody.
|
||||
let outerIdentity = await this.store.resolveResume(hostId, credential)
|
||||
if (abandonedByClient('assignment')) return
|
||||
if (!outerIdentity) {
|
||||
outerIdentity = await this.store.resolveInviteForMove(hostId, credential)
|
||||
if (abandonedByClient('assignment')) return
|
||||
}
|
||||
const assignment = outerIdentity
|
||||
? await this.assignments.resolve({ userId: outerIdentity.userId, relayHostId: hostId })
|
||||
: null
|
||||
|
||||
Reference in New Issue
Block a user