Compose services¶
ordeal explore --runner compose tests a running application instead of calling
one Python function at a time.
In plain English: ordeal starts your services, uses them like a client would, breaks selected things between requests, and checks whether the application recovers. If it finds a failure, it saves the exact sequence and tries that sequence several more times.
Who this is for¶
- An application developer with an API and one or more background workers.
- A tester who wants failures described as requests and service events.
- An SRE testing recovery before deployment.
- A library user calling
ComposeRunnerdirectly from Python. - A maintainer inspecting exact trace and replay semantics.
You do not need to understand containers deeply to start. You do need a working Compose file and one HTTP URL that ordeal can reach from the host.
Four useful terms¶
- Topology: the group of containers described by your Compose file.
- Fault window: the short period when ordeal intentionally broke something.
- Recovery request: the clean request sent after the service is restored.
- Trace: the saved ordered record of lifecycle, fault, and request actions.
Choose your path¶
| If you want to... | Read |
|---|---|
| Run a safe first experiment | Quickstart |
| Look up every setting and default | Configuration |
| Build create/read/update workflows | Stateful workflows |
| Understand exactly what each fault does | Fault model |
| Read or replay a saved failure | Traces and replay |
| Put the runner in CI | CI and operations |
| Fix an error or surprising result | Troubleshooting |
| Call the runner from Python | API reference |
The basic loop¶
For each configured operation, ordeal:
- Keeps the same Compose topology and scenario state alive.
- Selects an eligible HTTP request using the configured seed.
- Sometimes injects a configured worker or response fault.
- Sends a request during the fault window when the fault model calls for it.
- Restores or restarts the affected service.
- Sends a clean request and validates status, JSON expectations, and captures.
- Records the resolved request, fault, result, and state change.
This is useful for bugs such as "the API never recovers after its worker dies" or "the next request fails after a delayed response." It is not a hypervisor and it does not make Docker, the network, or your services deterministic.
Smallest useful config¶
[compose]
base_url = "http://127.0.0.1:8080"
health_path = "/health"
services = ["api", "worker"]
[[compose.requests]]
name = "list-items"
path = "/items"
Every run saves a trace under .ordeal/traces/. A failure also gets repeated
replay reporting such as attempted 5 / reproduced 3.
Keep credentials replayable without writing them to traces by using environment placeholders in headers or JSON bodies:
Ordeal resolves ${SERVICE_TOKEN} only at the HTTP transport boundary. Trace
serialization preserves the placeholder, redacts literal credential-shaped
fields and response authentication headers, and stores response hashes instead
of body previews. Do not put secrets in request paths or captured state.
What ordeal promises¶
- The saved action and fault order is exact.
- Resolved request inputs and failure signatures are recorded.
- Replay counts exact matches; it does not call a flaky replay deterministic.
- Containers that were already active are not taken down by cleanup.
- Named volumes are not deleted.
What it does not promise¶
- Deterministic process scheduling or network timing.
- Network partitions, CPU pressure, disk faults, or packet-level corruption.
- Correctness beyond your configured statuses and JSON expectations.
- A clean database between replay attempts.
- Safe use against production. Worker kill and restart are intentionally disruptive.
Start with the Quickstart, then use the reference pages only when you need their depth.