fix(relay): declare reconnection to the director's verified fast lane (#12086)

Recovery and broker open now send the optional reconnect hint so the
director admits already-assigned hosts through its bounded fast lane
(orca-cloud#212) instead of the placement queue that starved session
recovery during the 2026-08 incident. A rolled-back director that
rejects the hinted field gets one unhinted retry.

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
This commit is contained in:
Jinwoo Hong 2026-08-02 01:39:03 -07:00 committed by GitHub
parent 3f8654c26e
commit 5390224bf7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 72 additions and 1 deletions

View File

@ -56,6 +56,59 @@ describe('relay HTTP client', () => {
expect(fetch.mock.calls[0]?.[1]?.signal).toBeInstanceOf(AbortSignal)
})
it('declares reconnection in the assignment body when hinted', async () => {
const fetch = vi.fn<typeof globalThis.fetch>(async () =>
Response.json({
v: 1,
cellUrl: 'https://relay-c1.example',
assignmentEpoch: 4,
lease: 'lease-jwt'
})
)
await expect(
requestRelayAssignment({
directorUrl: 'https://relay.example',
relayToken: 'scoped-token',
relayHostId: 'AbCdEf0123_-xyZ9',
reconnect: true,
fetch
})
).resolves.toMatchObject({ assignmentEpoch: 4 })
expect(JSON.parse(String(fetch.mock.calls[0]?.[1]?.body))).toEqual({
v: 1,
relayHostId: 'AbCdEf0123_-xyZ9',
reconnect: true
})
})
it('retries once unhinted when a rolled-back director rejects the hint', async () => {
const fetch = vi
.fn<typeof globalThis.fetch>()
.mockResolvedValueOnce(Response.json({ error: 'invalid_request' }, { status: 400 }))
.mockResolvedValueOnce(
Response.json({
v: 1,
cellUrl: 'https://relay-c1.example',
assignmentEpoch: 4,
lease: 'lease-jwt'
})
)
await expect(
requestRelayAssignment({
directorUrl: 'https://relay.example',
relayToken: 'scoped-token',
relayHostId: 'AbCdEf0123_-xyZ9',
reconnect: true,
fetch
})
).resolves.toMatchObject({ assignmentEpoch: 4 })
expect(fetch).toHaveBeenCalledTimes(2)
expect(JSON.parse(String(fetch.mock.calls[1]?.[1]?.body))).toEqual({
v: 1,
relayHostId: 'AbCdEf0123_-xyZ9'
})
})
it('aborts a blackholed assignment request so recovery can retry', async () => {
const fetch = vi.fn<typeof globalThis.fetch>(
async (_url, init) =>

View File

@ -116,6 +116,7 @@ export async function requestRelayAssignment(input: {
directorUrl: string
relayToken: string
relayHostId: string
reconnect?: boolean
fetch?: typeof globalThis.fetch
requestDeadlineMs?: number
}): Promise<RelayAssignment> {
@ -129,11 +130,21 @@ export async function requestRelayAssignment(input: {
'content-type': 'application/json'
},
signal: AbortSignal.timeout(input.requestDeadlineMs ?? RELAY_HTTP_REQUEST_DEADLINE_MS),
body: JSON.stringify({ v: 1, relayHostId: input.relayHostId })
body: JSON.stringify({
v: 1,
relayHostId: input.relayHostId,
// Declares likely reconnection so the director can verify and admit
// through its bounded fast lane instead of the placement queue.
...(input.reconnect ? { reconnect: true } : {})
})
})
if (!response.ok) {
const retryAfterMs = relayRetryAfterMs(response.headers.get('retry-after'))
await cancelUnreadResponseBody(response)
if (input.reconnect && response.status === 400) {
// A rolled-back director rejects unknown fields; retry once unhinted.
return await requestRelayAssignment({ ...input, reconnect: false })
}
throw new RelayHttpError('assignment', response.status, retryAfterMs)
}
const parsed = AssignmentResponseSchema.safeParse(await response.json())

View File

@ -163,6 +163,9 @@ export class RelayOriginPool {
directorUrl: this.options.directorUrl,
relayToken: this.relayJwt,
relayHostId: this.options.relayHostId,
// Recovery always follows an established assignment; the director
// verifies this and admits through its reconnect fast lane.
reconnect: true,
fetch: this.options.fetch
})
this.assertCurrent()

View File

@ -208,6 +208,10 @@ export class RelaySessionBroker {
directorUrl: this.options.authConfig.relayDirectorUrl,
relayToken: authorization.relayToken,
relayHostId: this.relayHostId,
// Any previously paired host likely holds a durable assignment; the
// director verifies the claim, and first-ever pairing simply falls
// through to the placement lane.
reconnect: true,
fetch: this.options.fetch
})
this.assertCurrent()