From 90f891cf4d4a312e1d1437bcce110d41aa200d3f Mon Sep 17 00:00:00 2001 From: JSONbored <49853598+JSONbored@users.noreply.github.com> Date: Tue, 7 Jul 2026 01:40:43 -0700 Subject: [PATCH] fix(selfhost): make orb-relay-drain resilient to broker degradation The drain loop's 15s AbortSignal.timeout matched its 15s setInterval, so a degraded broker (slow responses or HTTP 500s) caused overlapping drain calls to pile up and immediate timeouts with no buffer. Raise the request timeout to 30s, add an in-flight guard so a tick is skipped while the previous drain is still running, and match the poll interval to the new timeout. Fixes GITTENSORY-1C. --- src/orb/broker-client.ts | 2 +- src/server.ts | 31 ++++++++++++++++++++----------- 2 files changed, 21 insertions(+), 12 deletions(-) diff --git a/src/orb/broker-client.ts b/src/orb/broker-client.ts index 003e599bf6..9edd6d6371 100644 --- a/src/orb/broker-client.ts +++ b/src/orb/broker-client.ts @@ -250,7 +250,7 @@ export async function drainOrbRelay( method: "POST", headers: { authorization: `Bearer ${env.ORB_ENROLLMENT_SECRET}`, "content-type": "application/json" }, body: JSON.stringify({ ack }), - signal: AbortSignal.timeout(15_000), + signal: AbortSignal.timeout(30_000), }); if (!res.ok) throw new Error(`orb_relay_drain_http_${res.status}`); const body = (await res.json()) as { events?: Array<{ deliveryId?: unknown; eventName?: unknown; rawBody?: unknown }> }; diff --git a/src/server.ts b/src/server.ts index bb25698c64..12a5eae69d 100644 --- a/src/server.ts +++ b/src/server.ts @@ -1007,25 +1007,34 @@ async function main(): Promise { const { drainOrbRelay } = await import("./orb/broker-client"); const { enqueueWebhookByEnv } = await import("./github/webhook"); /* v8 ignore start -- pull-mode relay loop is a live self-host timer; monitor semantics are covered in selfhost tests. */ + let drainInFlight = false; const drainRelay = async (): Promise => { - await drainOrbRelayWithMonitor({ - state: relayDrainState, - relayEnv: { - ORB_ENROLLMENT_SECRET: process.env.ORB_ENROLLMENT_SECRET, - ORB_BROKER_URL: process.env.ORB_BROKER_URL, - }, - env, - drain: drainOrbRelay, - enqueue: enqueueWebhookByEnv, - }); + if (drainInFlight) return; + drainInFlight = true; + try { + await drainOrbRelayWithMonitor({ + state: relayDrainState, + relayEnv: { + ORB_ENROLLMENT_SECRET: process.env.ORB_ENROLLMENT_SECRET, + ORB_BROKER_URL: process.env.ORB_BROKER_URL, + }, + env, + drain: drainOrbRelay, + enqueue: enqueueWebhookByEnv, + }); + } finally { + drainInFlight = false; + } }; void drainRelay(); + // 30s matches broker-client's request timeout so a slow/degraded broker's in-flight drain has fully + // timed out (or completed) before the next tick would otherwise pile another request on top of it. setInterval( () => void drainRelay().catch((error) => captureError(error, { kind: "orb_relay_drain" }), ), - 15_000, + 30_000, ); /* v8 ignore stop */ }