Purrx

Timeouts and deadlines

Stop waiting on a model call that hangs, cancel the request with an AbortSignal, and keep retries inside a deadline so serverless functions fail cleanly instead of being killed.

12 min+35 XPHands-on

Retries handle calls that fail. Some calls don't fail: they just never answer. A request stuck for five minutes holds a user's spinner, and on a serverless host, it holds the whole request until the host kills it.

Serverless limit · 300s (the host kills the request)

Deck deadline · 240s

outline ≤ 90swaitdeck ≤ 90s
Time limits nest. Each model call gets 90s, the whole deck gets 240s, and the host kills the request at 300s. A retry that would cross the deadline fails early, with a real error message.

A timeout for one call

withTimeout(fn, ms) races fn against a timer. If the timer wins, it rejects with a TimeoutError, which classifyError already treats as retryable.

Rejecting isn't enough on its own: the request would keep running in the background, still costing tokens. So fn gets an , the model call receives it, and the timer aborts it.

how the pipeline will use it
withTimeout((signal) => model.invoke(messages, { signal }), 90_000)

A deadline for the whole job

Hosts like Vercel give a a hard limit, say 300 seconds. Three calls of 90 seconds each, with retries and waits between them, can pass it. So withRetry gets a : a timestamp. Before waiting, it checks whether the wait would end after the deadline. If so, it throws the real error right away.

Key takeaways

  • Give every model call a timeout, and pass an AbortSignal so the request is really canceled.
  • A deadline covers the whole job: all attempts and all waits between them.
  • Fail before the host's time limit, with a real error, instead of being killed mid-request.

Sign in to run the exercise

Reading is free. Writing code here needs an account so we have somewhere to keep your Gemini key and the +35 XP you are about to earn.