Resilience patterns (timeouts, retries, circuit breakers)
Purpose: Stop upstream failures from cascading into AEM outages, with patterns sized for a render-thread world.
Who this page is for
| Audience | Why it matters to you |
|---|---|
| Backend engineers | Required for any production integration |
The failure you are designing against
Publish has a finite render thread pool. If threads block on a sick upstream, page rendering stops for everyone — an external dependency outage becomes a full site outage. Every pattern below defends that pool.
The pattern stack
| Pattern | Rule of thumb |
|---|---|
| Timeout | Total budget per render-path call ≤ ~1s; jobs can afford more |
| Retry | Only idempotent calls; max 1–2 attempts; never retry on the render path (multiplies latency) |
| Circuit breaker | After N failures, fail fast for a cool-down; render path gets the fallback instantly |
| Bulkhead | Separate pools/limits per upstream so one bad system can't starve another |
| Fallback | Defined per feature: cached last-good value, static message, hidden module |
render thread ──▶ [breaker CLOSED?] ──▶ call (800ms timeout) ──▶ ok
│ OPEN │ timeout/5xx
▼ ▼
cached/fallback ◀── record failure (trip after N)
A small resilience library (or a well-tested homegrown breaker in an OSGi service) is fine — the discipline matters more than the tooling.
Fallback design with the PHI example
| Feature | Fallback |
|---|---|
| Live premium quote on plan page | Last-cached premium + "indicative price" label |
| Plan comparison (rating engine) | Static comparison table from Content Fragment data |
| Live chat availability | Hide the widget |
Fallbacks are product decisions — agree them with the product owner at design time, not during the incident.
Verification
Chaos-test in stage: block the upstream (firewall rule), then confirm pages render with fallbacks, threads recover, and the breaker closes when the upstream returns. See load testing.