{
  "docVersion": 1,
  "id": "template-retry-storm-anti-pattern",
  "name": "Retry storm — cascade in progress",
  "purpose": "An anti-pattern reference: synchronized client retries, mismatched timeout layers, a cache stampede and unbounded queues turning one slow database into a full cascading failure.",
  "nodes": {
    "users": {
      "type": "users",
      "label": "10k clients",
      "x": 20,
      "y": 230,
      "runtime": "retry ×3 · no jitter",
      "color": "amber"
    },
    "lb": {
      "type": "lb",
      "label": "Load balancer",
      "x": 260,
      "y": 230,
      "runtime": "healthy — and helpless"
    },
    "api": {
      "type": "k8s",
      "label": "API",
      "x": 510,
      "y": 230,
      "runtime": "timeout: 30s (!)",
      "color": "amber",
      "notes": "Fatal mismatch: the API works up to 30s on requests whose callers gave up at 3s. Every thread is a zombie."
    },
    "cache": {
      "type": "cache",
      "label": "Cache",
      "x": 760,
      "y": 80,
      "runtime": "TTL expired at :00",
      "color": "red",
      "style": "dashed",
      "notes": "All keys share one TTL. At the top of the hour they expire together and every request becomes a DB miss."
    },
    "db": {
      "type": "database",
      "label": "Database",
      "x": 1010,
      "y": 230,
      "runtime": "connections exhausted",
      "color": "red",
      "style": "dashed"
    },
    "svcb": {
      "type": "server",
      "label": "Service B",
      "x": 760,
      "y": 400,
      "runtime": "unbounded queue · growing",
      "color": "amber",
      "notes": "No load shedding: its queue absorbs the overflow until its own latency breaches every caller's timeout too."
    }
  },
  "edges": {
    "e1": {
      "from": "users",
      "to": "lb",
      "fromSide": "right",
      "toSide": "left",
      "label": "3s timeout · retry ×3 · no jitter",
      "animated": true,
      "color": "red"
    },
    "e2": {
      "from": "lb",
      "to": "api",
      "fromSide": "right",
      "toSide": "left",
      "label": "waves, not a stream",
      "animated": true,
      "color": "red"
    },
    "e3": {
      "from": "api",
      "to": "cache",
      "fromSide": "right",
      "toSide": "left",
      "label": "all keys miss at once",
      "style": "dashed",
      "color": "red"
    },
    "e4": {
      "from": "api",
      "to": "db",
      "fromSide": "right",
      "toSide": "left",
      "label": "herd: 10k misses together",
      "animated": true,
      "color": "red"
    },
    "e5": {
      "from": "api",
      "to": "svcb",
      "fromSide": "bottom",
      "toSide": "left",
      "label": "30s inner vs 3s outer",
      "color": "amber"
    },
    "e6": {
      "from": "svcb",
      "to": "db",
      "fromSide": "right",
      "toSide": "bottom",
      "label": "still working for dead callers",
      "style": "dashed",
      "color": "amber"
    }
  },
  "boxes": {
    "b1": {
      "x": 480,
      "y": 20,
      "w": 730,
      "h": 540,
      "label": "cascading failure domain — spreading left",
      "color": "red",
      "opacity": 0.04
    }
  },
  "texts": {
    "t1": {
      "x": 20,
      "y": 420,
      "text": "four mistakes, one outage:\n1. no jitter → retries arrive as synchronized waves\n2. inner timeout > outer → zombie work fills every thread\n3. shared TTL → cache stampede at the worst moment\n4. no retry budget → load ×4 exactly when capacity is lowest",
      "color": "red",
      "size": 12
    },
    "t2": {
      "x": 20,
      "y": 590,
      "text": "the fix is the 'Anatomy of a safe RPC' template:\njittered backoff · timeout ladder · retry budgets ·\nstampede protection · load shedding.",
      "color": "green",
      "size": 12
    }
  },
  "meta": {
    "createdAt": "2026-07-13T09:00:00.000Z",
    "modifiedAt": "2026-07-13T09:00:00.000Z"
  }
}