Skip to content
Latchkey

Self-Healing CI: Recovering Flaky External-Service Integration Tests

When an integration test fails because the external service it calls was briefly slow or unavailable, the flake is upstream - the same test passes on a clean retry.

The problem

An integration test that exercises a real external service (an API, a sandbox endpoint, a third-party dependency) fails intermittently with a timeout, a 5xx, or a rate-limit from that service. Your code and the test are correct; a human re-runs the suite and it goes green with no change.

Typical symptom
AssertionError: expected 200 but got 503 from https://sandbox.payments.example/charge
# or
TimeoutError: external service did not respond within 5000ms

Why it happens

Integration tests deliberately depend on systems you do not control. Those services have their own load, rate limits, and brief outages, so a test can fail on the dependency’s condition rather than on a regression in your code.

Blindly retrying every failure is risky - it can hide a real contract break - so the goal is to retry only the failures whose signature matches a transient upstream problem, not an assertion that consistently fails.

The manual fix

Manual handling for externally-driven flakiness:

  1. Re-run the suite and confirm the failure does not reproduce.
  2. Add a bounded retry around calls to the external dependency, with backoff.
  3. Where feasible, stub or mock the external service so the test does not depend on its live availability.

How this gets automated

Self-healing CI treats external-dependency flakiness conservatively: it identifies failures that match a transient upstream signature (timeout, 5xx, rate-limit from the service) and retries those specifically, while leaving consistent, reproducible assertion failures to surface as real. The aim is to remove upstream noise without ever masking a genuine contract or logic regression.

Related guides

Tired of flaky CI? Latchkey auto-heals failed jobs and retries them for you. Start free →