Skip to content

feat(tripwire): in-memory SWR on the page, per-call timeouts on the crons#30

Merged
n2p5 merged 1 commit into
mainfrom
fix/cache-and-timeouts
May 3, 2026
Merged

feat(tripwire): in-memory SWR on the page, per-call timeouts on the crons#30
n2p5 merged 1 commit into
mainfrom
fix/cache-and-timeouts

Conversation

@n2p5
Copy link
Copy Markdown
Contributor

@n2p5 n2p5 commented May 3, 2026

Summary

Three targeted changes against the persistent "first outbound call hangs" pattern we see in production logs:

`src/lib/tripwire/aggregates.ts` — page-side SWR

  • Module-level memory cache, 2-minute TTL.
  • Warm hits return synchronously, no SDK call.
  • Stale hits return cached value immediately and queue a background refresh via `after()` — next request sees fresh data.
  • Cold instances wait for the fetch. Each attempt is bounded by an `AbortSignal` + 5s timeout. Up to 2 attempts. If both fail, throw — Suspense's error boundary surfaces it.

`src/lib/tripwire/ingest.ts` — per-call timeouts

  • `list()` wrapped in `AbortSignal` + 10s timeout, 1 retry on timeout (paginated, can't make partial progress without retrying).
  • Per-event `get()` wrapped in `AbortSignal` + 10s timeout, no retry. A bad event blob just gets logged + skipped; the next cron tick reprocesses unknown ids.
  • Existing batch-level deadline guard (240s) unchanged.

`src/lib/tripwire/stats.ts` — parallelize, don't retry

  • The six SELECTs and the ASN reader fetch are independent. Fire them all in parallel via `Promise.all`. Wall-clock is now `max(individual)` instead of `sum`.
  • No internal timeouts. The cron route's `maxDuration` is the outer bound; the existing structured logs already show where a hang happens.

Verified through `next dev`

Path Time
Page cold 602ms (blob fetch + render, 142 real events)
Page warm 62ms (cache hit, no SDK call)
build-stats 1.7s (parallelized)
ingest 301ms

171 unit tests pass · build clean · lint clean.

@vercel
Copy link
Copy Markdown

vercel Bot commented May 3, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
func-lol Ready Ready Preview, Comment May 3, 2026 0:11am

Request Review

src/lib/tripwire/aggregates.ts: module-level singleton with a 2-minute
TTL. The build-stats cron republishes stats/tripwire-aggregates.json
every ~15 minutes, so a warm Fluid Compute instance only pays for the
blob fetch once per 2-minute window. On TTL expiry the next request
triggers a fresh fetch. On any fetch error we throw and let the error
boundary surface it — no stale fallback, since silently lying about
freshness is worse than a visible failure.

src/app/x/tripwire/error.tsx: client error boundary for the route.
Surfaces the error message and a retry button instead of leaving the
page stuck on a Suspense skeleton when getAggregates() throws.

src/lib/tripwire/aggregates.test.ts: four cases — cache miss fetches,
cache hit within TTL skips the fetch, expired TTL re-fetches, and
non-200 status throws.

src/proxy.test.ts: spread real @vercel/blob exports into each
mock.module() call so the module shape stays stable for tests in
other files that import list/get/etc.
@n2p5 n2p5 force-pushed the fix/cache-and-timeouts branch from cbb9fdc to 750ff2c Compare May 3, 2026 12:10
@n2p5 n2p5 merged commit 0db7968 into main May 3, 2026
7 checks passed
@n2p5 n2p5 deleted the fix/cache-and-timeouts branch May 3, 2026 18:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant