Skip to content

fix(orb-relay): isolate per-event enqueue failures in the pull-mode drain loop so one throwing event doesn't abort the rest of the batch #3813

Description

@JSONbored

Context

Found during the 2026-07-06 incident audit (parent: #1667). drainOrbRelayWithMonitor (src/selfhost/monitored-work.ts) iterates over relayed events and calls args.enqueue(...) for each with no try/catch around the call. enqueueWebhookByEnv swallows its own anticipated failures (missing queue binding, queue send failure) and returns a string result rather than throwing — but two of its recordWebhookEvent calls are not wrapped in try/catch, so a D1/Postgres write failure there (exactly the class of failure a D1-near-cap or Postgres-blip scenario produces) throws uncaught out of enqueueWebhookByEnv, up through this for-loop, aborting the entire remaining batch for that drain tick. Every event still in the batch after the failing one is never attempted this tick.

This is a distinct bug from the "malformed event silently filtered" issue (already covered in #3812) — this one is a downstream write failure propagating up and killing sibling events that were otherwise perfectly valid.

Requirements

  • Wrap the args.enqueue(...) call inside drainOrbRelayWithMonitor's loop in its own try/catch, so one event's failure logs + increments a per-event failure metric and continues to the next event, instead of throwing out of the whole batch.
  • Ensure a per-event enqueue exception does not get added to pendingAck (so it is retried on the next drain, consistent with the existing "enqueue_failed" non-throwing handling).
  • Add a test asserting that when enqueue throws for the 2nd of 3 events in a drain batch, events 1 and 3 both still get processed/acked appropriately rather than the whole tick aborting after event 2.

Deliverables

  • src/selfhost/monitored-work.ts: try/catch around the enqueue call in drainOrbRelayWithMonitor's loop.
  • test/unit/selfhost-monitored-work.test.ts: new case for a mid-batch enqueue throw.

Expected outcome

A single event's downstream write failure during pull-mode relay drain no longer silently discards every subsequent event in that same batch; each event is isolated and independently retried or acked.

Metadata

Metadata

Assignees

Labels

maintainer-onlyOwner-only work — yields no Gittensor points.

Projects

Status
Done

Relationships

None yet

Development

No branches or pull requests

Issue actions