BitBootcampBitBootcamp ← all explainers 🔄 Review ⚙ Settings

Drill 15 — The $40k Weekend

Theme: LLM & Agent Incidents · Format: 20-min drill · Difficulty: intro

The story

Friday afternoon: a new document-reprocessing job ships. Saturday 2 a.m.: a malformed batch makes the job fail — and retry. No backoff, no max attempts, and each retry reprocesses the entire batch through the LLM API. Billing data lags a day; no one set a spend alert anyway. Monday 9 a.m.: someone opens the cloud console.

⏸ Stop here and ask the room: how much, and what three missing guardrails does this story name?

Run it — facilitator script

Timing: 2 min story · 10 min questions · 3 min reveal · 5 min transfer.

Where should cost visibility come from if the provider's billing lags?

Listen for: From your own side of the wire — count tokens and requests at dispatch time, emit them as metrics like any other SLI (Service Level Indicator), and alarm on spend-rate anomalies in near-real time. The provider's invoice is reconciliation, not monitoring.

Weak signal: "Set up billing alerts in the cloud console" — which the story already tells you lag a day; or treating cost as finance's month-end problem rather than an operational signal that pages someone.

What's the difference between a retry policy and a retry budget?

Listen for: A policy says how to retry — backoff, jitter, which errors qualify. A budget says how much in total — max attempts, max spend, max wall-clock — and what happens at the ceiling: park the input in a dead-letter queue, page a human. A policy without a budget is an unbounded loop wearing a best practice as a costume.

Weak signal: "We use exponential backoff" offered as a complete answer — backoff spreads the cost over time, it doesn't bound it. The $40k arrives slightly later.

What's the kill switch — and who can pull it at 2 a.m. Sunday?

Listen for: A named mechanism — feature flag, queue pause, revocable API key, scale-to-zero — that stops spend in one action, documented in the runbook, executable by whoever is on-call without waking an owner or hunting for credentials.

Weak signal: "We'd redeploy with the job disabled" — a 40-minute pipeline is not a kill switch; or naming a person ("Dave could stop it") instead of a mechanism anyone on rotation can operate.

The reveal

$40k of identical failed work. The job never succeeded once after the first failure — forty thousand dollars of retrying the same poison batch.

Why this happens — the mechanics

LLM (Large Language Model) providers meter usage per token and aggregate it asynchronously — spend typically lands in consoles and exports hours to a day later. The natural feedback loop, someone seeing a bill, operates on a timescale of days, while the failure operates on a timescale of seconds. Unless you meter from your own side, there is no signal in between.

The amplification comes from retry granularity. The job retries at batch level, so one poison document re-buys the entire batch through a per-token-priced API on every attempt. Do the multiplication — attempts per hour × tokens per batch × price per token × 55 hours — and $40k stops being surprising. And unlike a database that would fall over under this load, the API provides no natural backpressure: it happily accepts infinite paid work, all weekend, without a single error you didn't cause yourself.

The last ingredient is the calendar. A poison input fails deterministically, so retry-until-success is a loop with no exit except a human — and the humans are gone from Friday afternoon to Monday morning. MTTD (Mean Time To Detect) for a cost incident is bounded by office hours unless a machine is watching the meter.

Diagrams

Problem — how the failure unfolds:

sequenceDiagram
    autonumber
    participant JB as Job
    participant API as LLM API
    participant BIL as Billing
    participant OC as On-call
    Note over JB: Friday afternoon -<br/>reprocessing job ships
    JB--xAPI: Saturday 2 a.m. -<br/>poison batch fails
    loop No backoff, no max attempts
        JB->>API: Reprocess the entire batch
        API--xJB: Same failure, full<br/>price (silent)
    end
    Note over BIL: Spend data lags a day - no<br/>alert configured (silent)
    Note over OC: Weekend passes -<br/>nobody paged
    OC->>BIL: Monday 9 a.m. - opens<br/>the cloud console
    BIL-->>OC: $40k of identical<br/>failed work

Solution — where the guardrails go:

flowchart TD
    A["Poison batch fails the job"] --> B["Retry with exponential backoff"]
    B --> C["Retry budget: hard ceiling<br/>on attempts"]
    C -->|"budget exhausted"| D["Batch parked in dead-<br/>letter queue (DLQ)"]
    D --> E["Pipeline continues on<br/>healthy work"]
    B --> F["Self-side token meter<br/>counts tokens and requests<br/>as dispatched"]
    F --> G["Hard budget cap halts the<br/>workload automatically"]
    F -.-> H["Near-real-time spend alarm<br/>pages on-call"]
    H -.-> I["Runaway detected Saturday<br/>2:15 a.m., cost bounded"]

What good looks like

The lesson

Cost is a production SLI: meter it from your side (tokens dispatched, requests counted) with near-real-time alarms and hard budget caps that stop the workload. Retries need backoff, budgets, and a dead-letter queue for poison inputs — a retry policy without a ceiling is a blank check.

Named concepts: cost SLOs, retry budgets, exponential backoff, dead-letter queues, kill switches.

Real-world echoes

Transfer

What's the maximum our LLM/API spend could reach between "runaway starts" and "first human notices"? Compute it — the number is usually alarming.

Make it a ticket: For each LLM-calling workload, compute that worst-case number and attach it to the service's runbook; any workload where the answer exceeds a day's normal spend gets a budget cap and a kill switch ticket this sprint.

Related