Deterministic Replay via Replay Tokens
Turn nondeterministic logs into repeatable test runs with replay tokens.
šÆ Capture a Replay Token that bundles state, random seeds, and timestamps so you can replay a distributed run exactly as it happenedāgreat for debugging flaky bugs, performance regressions, and safetyācritical systems.
šÆ System Scenario & Requirements
System Goal
šÆ Capture a Replay Token that bundles state, random seeds, and timestamps so you can replay a distributed run exactly as it happenedāgreat for debugging flaky bugs, performance regressions, and safetyācritical systems.
Actors & Components
- Production Nodes
- Replay Engine
- Service A
- Service B
- Immutable Log
- Replay Token
Functional Requirements
- šÆ Capture a Replay Token that bundles state, random seeds, and timestamps so you can replay a distributed run exactly as it happenedāgreat for debugging flaky bugs, performance regressions, and safetyācritical systems.
- In a distributed system, logs are a mix of deterministic events (message receipts, state changes) and nondeterministic ones (random backāoffs, clockādrift, outāofāorder network packets).
- When a bug surfaces, the original trace is often a oneāoff, making āwhatāifā debugging impossible.
Constraints & Assumptions
- Operational latency, consistency levels, and network partition boundaries must be enforced.
ā” Execution Stages & Decision Trace
Stage 1 ā Solution: Replay Tokens + Immutable Event Store
A Replay Token is a lightweight, immutable payload that represents the exact execution context of a run: During normal execution, every node: 1.
Logs every outbound event to an immutable event store (e.g., Kafka, Pulsar, or a custom writeāonce file).
Deep Dive
Deep Dive: Stage 1 ā Solution: Replay Tokens + Immutable Event Store
A Replay Token is a lightweight, immutable payload that represents the exact execution context of a run:
| Field | Purpose |
run_id | Unique identifier for the run |
seed | Seed for all pseudorandom generators |
timestamp_offset | Offset to align logical clocks |
event_hash | Merkle root of the event stream |
During normal execution, every node:
- Logs every outbound event to an immutable event store (e.g., Kafka, Pulsar, or a custom writeāonce file).
- Captures the deterministic parts of its state (e.g., local counters, configuration).
- Generates a
ReplayTokenafter the run finishes, hashing the event stream and bundling the seed.
To replay:
- Feed the event stream back into the same processing pipeline.
- Seed all random number generators with the tokenās
seed. - Apply the
timestamp_offsetto normalise logical timestamps.
Because the event stream is immutable and the seed is fixed, the replay will follow the exact same branching path as the original run, even under a different network or hardware configuration.
Observable outcome: Because the event stream is immutable and the seed is fixed, the replay will follow the exact same branching path as the original run, even under a different network or hardware configuration.
Deep Dive: Stage 2 ā Architecture Kit Diagram
Observable outcome: You can explain how āArchitecture Kit Diagramā changes the architecture or implementation path.
Deep Dive: Stage 3 ā Code Sample: Generating a Replay Token (Go)
type ReplayToken struct {
RunID string `json:"run_id"`
Seed int64 `json:"seed"`
TimestampOffset time.Duration `json:"timestamp_offset"`
EventHash string `json:"event_hash"`
}
func generateReplayToken(events []Event, seed int64) ReplayToken {
// Hash the event payloads for integrity
h := sha256.New()
for _, e := range events {
h.Write([]byte(e.Payload))
}
return ReplayToken{
RunID: uuid.New().String(),
Seed: seed,
TimestampOffset: time.Since(events[0].Timestamp),
EventHash: hex.EncodeToString(h.Sum(nil)),
}
}
Observable outcome: You can explain how āCode Sample: Generating a Replay Token (Go)ā changes the architecture or implementation path.
Deep Dive: Stage 4 ā Tradeāoffs
- Pros ā Precise debugging, regression testing, safety validation.
- Cons ā Requires storage for all events, slight performance overhead, and careful seed management.
Observable outcome: Cons ā Requires storage for all events, slight performance overhead, and careful seed management.
Deep Dive: Stage 5 ā Production Tips
- Persist the token alongside the event store so you can replay on demand.
- Encrypt tokens if sensitive data is included.
- Version your event schema; include a
schema_versionin the token.
With a deterministic replay token in hand, you can turn any flaky distributed bug into a reproducible, testable scenarioāmaking debugging a lot less mysterious.
Observable outcome: With a deterministic replay token in hand, you can turn any flaky distributed bug into a reproducible, testable scenarioāmaking debugging a lot less mysterious.
š System Outcome & Trade-offs
Observed User & Operator Behavior
User: Clients observe deterministic state without lost updates or race conditions.
Operator: Operators can verify stage outcomes against the scenario requirements.
Key Architectural Trade-offs
- System guarantees are traded against replication overhead and failover convergence times.
Key learnings
- A Replay Token is a lightweight, immutable payload that represents the exact execution context of a run: During normal execution, every node: 1.
- Apply cqrs-and-event-sourcing to Architecture Kit Diagram.
- Apply cqrs-and-event-sourcing to Code Sample: Generating a Replay Token (Go).
- Pros ā Precise debugging, regression testing, safety validation.
Apply Concepts from this Scenario
Test your understanding of the architecture decisions and trade-offs presented in this case study.
