mirror of
https://github.com/stablyai/orca.git
synced 2026-09-27 16:02:35 +00:00
* fix(relay): stop taking the fleet-wide cell inventory lock on per-connection paths activateControl, acquireActivity, changeActivity and removeSupersededSameCellControls each adjust exactly one cell's reservation, yet took SELECT * FROM relay_cells FOR UPDATE, so every desktop rebind and phone reconnect in the fleet queued behind every other one and behind placement. They now use the single-row atomic update (or lock only their own cell row), leaving the inventory lock to placement and sweeps. Fleet-wide 55P03 retries ran p50 430 / p99 1320 per five minutes on 2026-09-03, every cell pinned sqlLatencyMsMax at the lock timeout, and the old cell image crashed on the resulting pool timeouts ~every 15 minutes. A real-Postgres test holds another cell's row and asserts a rebind proceeds; re-adding the inventory lock fails it. * fix(relay): lock the touched cell rows in order on cross-cell activity moves Review found that acquireActivity's existing-lease branch could lock the old lease's cell row (via removeActivityLease) before the new cell's row, which cycles with placement's ascending inventory lock; reproduced on real Postgres as paired 55P03 retries. lockCellRows now takes the one or two rows a per-connection path touches in cell_id order with the 500 ms request bound, and the census fails on any inline relay_cells FOR UPDATE outside the named lock helpers. A three-cell Postgres test moves an activity from the highest cell to a lower one while the target row is held and asserts the mover holds nothing else; five revert-mutants (inventory lock on each path, dropped ordering, dropped ORDER BY) fail it. * test(relay): make the inline relay_cells lock census scan whole statements Review showed two evasions: a FOR UPDATE inside query() and a queryLocked whose FROM relay_cells sat past a fixed line window. The guard now matches every query()/queryLocked() template statement in full; both evasions fail it. Also clears relay_cell_connection_snapshots in the connection- headroom Postgres suite so an aborted run does not poison the next.
135 lines
4.8 KiB
TypeScript
135 lines
4.8 KiB
TypeScript
import { afterAll, beforeAll, describe, expect, it } from 'vitest'
|
|
import { RelayAssignmentStore } from './assignment-store.js'
|
|
import { openRelayDatabase, type RelayDatabase } from './database.js'
|
|
|
|
const databaseUrl = process.env.ORCA_RELAY_TEST_POSTGRES_URL
|
|
const describePostgres = databaseUrl ? describe : describe.skip
|
|
const cell = {
|
|
id: 'control-supersession-postgres',
|
|
url: 'https://control-supersession-postgres.example.com',
|
|
capacityRequests: 1_000,
|
|
connectionHardCap: 600 as const,
|
|
connectionUnobservedBound: 50
|
|
}
|
|
const identity = {
|
|
userId: 'control-supersession-postgres-user',
|
|
relayHostId: 'supersedehost001'
|
|
}
|
|
|
|
describePostgres('PostgreSQL control supersession', () => {
|
|
const databases: RelayDatabase[] = []
|
|
|
|
beforeAll(async () => {
|
|
databases.push(
|
|
await openRelayDatabase({ databaseUrl, dataDir: '' }),
|
|
await openRelayDatabase({ databaseUrl, dataDir: '' })
|
|
)
|
|
})
|
|
|
|
afterAll(async () => {
|
|
const database = databases[0]
|
|
if (database) {
|
|
await database.query(
|
|
`DELETE FROM relay_control_connection_reservations WHERE user_id = ?`,
|
|
[identity.userId]
|
|
)
|
|
await database.query(
|
|
`DELETE FROM relay_assignment_activity_leases WHERE user_id = ?`,
|
|
[identity.userId]
|
|
)
|
|
await database.query(`DELETE FROM relay_assignments WHERE user_id = ?`, [identity.userId])
|
|
// A snapshot left by an aborted run rejects the replayed watermark with stale_connection_snapshot.
|
|
await database.query(`DELETE FROM relay_cell_connection_snapshots WHERE cell_id = ?`, [
|
|
cell.id
|
|
])
|
|
await database.query(`DELETE FROM relay_cell_connection_runtime WHERE cell_id = ?`, [cell.id])
|
|
await database.query(`DELETE FROM relay_cell_connection_limits WHERE cell_id = ?`, [cell.id])
|
|
await database.query(`DELETE FROM relay_cell_runtime WHERE cell_id = ?`, [cell.id])
|
|
await database.query(`DELETE FROM relay_cells WHERE cell_id = ?`, [cell.id])
|
|
}
|
|
for (const connection of databases) await connection.close()
|
|
})
|
|
|
|
it('serializes parallel generations into one durable control', async () => {
|
|
const stores = databases.map((database) => new RelayAssignmentStore(database, () => 100))
|
|
await stores[0]!.reconcileCells([cell])
|
|
await stores[0]!.recordCellHeartbeat({
|
|
cellId: cell.id,
|
|
cellUrl: cell.url,
|
|
cellIncarnation: '11111111-1111-4111-8111-111111111111',
|
|
startedAt: 50,
|
|
ready: true,
|
|
observedRequests: 0,
|
|
totalConnections: 0,
|
|
inFlightConnections: 0,
|
|
reservedConnectionUnits: 0,
|
|
enforcedConnectionUnits: 0,
|
|
connectionInclusionWatermark: 1,
|
|
connectionHardCap: 600,
|
|
connectionUnobservedBound: 50
|
|
})
|
|
const assignment = await stores[0]!.assign(identity)
|
|
|
|
await Promise.all([
|
|
stores[0]!.activateControl(identity, {
|
|
cellId: cell.id,
|
|
assignmentEpoch: assignment.assignmentEpoch,
|
|
generation: 1,
|
|
connectionInclusionWatermark: 10
|
|
}),
|
|
stores[1]!.activateControl(identity, {
|
|
cellId: cell.id,
|
|
assignmentEpoch: assignment.assignmentEpoch,
|
|
generation: 2,
|
|
connectionInclusionWatermark: 11
|
|
})
|
|
])
|
|
await databases[0]!.query(
|
|
`INSERT INTO relay_assignment_activity_leases
|
|
(user_id, relay_host_id, activity_id, activity_kind, cell_id,
|
|
request_units, expires_at, updated_at)
|
|
VALUES (?, ?, ?, 'control', ?, 1, 90100, 100),
|
|
(?, ?, ?, 'control', ?, 1, 90100, 100)`,
|
|
[
|
|
identity.userId,
|
|
identity.relayHostId,
|
|
`control:${cell.id}:100`,
|
|
cell.id,
|
|
identity.userId,
|
|
identity.relayHostId,
|
|
`control:${cell.id}:101`,
|
|
cell.id
|
|
]
|
|
)
|
|
await stores[0]!.activateControl(identity, {
|
|
cellId: cell.id,
|
|
assignmentEpoch: assignment.assignmentEpoch,
|
|
generation: 102,
|
|
connectionInclusionWatermark: 12
|
|
})
|
|
|
|
const controls = await databases[0]!.query(
|
|
`SELECT COUNT(*) AS count FROM relay_assignment_activity_leases
|
|
WHERE user_id = ? AND activity_kind = 'control'`,
|
|
[identity.userId]
|
|
)
|
|
expect(Number(controls[0]!.count)).toBe(1)
|
|
const assignments = await databases[0]!.query(
|
|
`SELECT reserved_controls FROM relay_assignments WHERE user_id = ?`,
|
|
[identity.userId]
|
|
)
|
|
expect(Number(assignments[0]!.reserved_controls)).toBe(1)
|
|
const cells = await databases[0]!.query(
|
|
`SELECT reserved_requests FROM relay_cells WHERE cell_id = ?`,
|
|
[cell.id]
|
|
)
|
|
expect(Number(cells[0]!.reserved_requests)).toBe(1)
|
|
const claims = await databases[0]!.query(
|
|
`SELECT claim_activity_id FROM relay_control_connection_reservations
|
|
WHERE user_id = ? AND state = 'claimed'`,
|
|
[identity.userId]
|
|
)
|
|
expect(claims).toEqual([{ claim_activity_id: `control:${cell.id}:102` }])
|
|
}, 15_000)
|
|
})
|