Introduction
An Event Replay System lets teams reprocess historical events (for bug fixes, model retraining, backfills, or new consumers) while keeping the production system and live users unaffected. Replaying events is a powerful tool — but it can be dangerous if done naively: you can duplicate side-effects, corrupt read models, or trigger external integrations twice.
This article provides a practical, senior-developer guide to design and implement a safe event replay system that supports:
Isolated replay environments (non-invasive)
Idempotent reprocessing and deduplication
Selective replay (time-range, aggregate, tenant, stream)
Versioned event handling and transformation
Controlled side-effect suppression or simulation
Metrics, audit, and cancelable runs
.NET worker and Angular control panel examples
The architecture assumes an event store (Kafka, EventStoreDB, Azure Event Hubs, or a durable SQL-backed log). Examples will use Kafka-style terminology but patterns apply to other stores.
Goals and Non-Goals
Goals
Reprocess events safely without impacting live consumers.
Provide repeatable, auditable replay jobs.
Allow filtering and transformation during replay.
Support dry-run, partial replay and replay with side-effect mitigation.
Provide UI controls for engineers (start, pause, stop, inspect).
Non-Goals
This is not a transactional backfill across multiple heterogeneous systems (that requires careful coordination).
We do not try to merge side-effects applied already into a single reconciliation engine — instead we provide tooling patterns to avoid double-effects.
High-Level Architecture
┌──────────────┐ ┌───────────────┐ ┌──────────────┐
│ Event Store │ ─────> │ Replay Worker │ ─────> │ Replay Sink │
│ (Kafka/ESDB) │ │ (.NET Service)│ │ (Read Model) │
└──────────────┘ └──────┬────────┘ └──────┬───────┘
│ │
▼ ▼
┌───────────┐ ┌────────────┐
│Control API│ <-------> │Angular UI │
└───────────┘ └────────────┘
Event Store: authoritative append-only log of domain events.
Replay Worker: reads events from store (earliest → latest or time window), transforms, and emits to replay sink instead of production sinks.
Replay Sink: isolated projection store, separate queues for test consumers, or a staging topic.
Control API and UI: start/stop/pause/replay runs, show metrics, configure transforms and filters.
Key Concepts
Isolated Replay
Events for replay should not be published to production sinks. Replay sinks include:
Separate projection tables (ReplayReadModel)
Separate Kafka topic namespaces (e.g.,
replay.*)Temporary message queues or simulation endpoints
Mocked external service adapters
Idempotency
Replay must be idempotent. Techniques:
Use idempotency keys derived from event metadata (eventId + replayRunId)
Persist processed event ids in a replay-specific dedupe store (fast key-value DB)
Make event handlers idempotent (upserts, delta-apply with checksums)
Side-Effect Management
Side-effects (emails, payments, third-party API calls) are managed by:
Suppression: disable actual side-effects during replay and log intended actions.
Simulation: route side-effects to a sandbox or mock service.
Replay Mode Awareness: handlers get a context flag
IsReplayand either avoid side-effects or call test endpoints.
Transformation & Versioning
Events may need transformation:
Versioned event schemas handled via event adapters or translators
Apply migration pipeline: V1 → V2 transforms during replay if consumer expects new shape
Controlled Replay
Allow operators to:
Specify filter:
stream,aggregateId,tenantId,time window, oroffset rangeRun a dry-run to see read-model impacts (without persisting)
Limit throughput (events/sec) to avoid resource exhaustion
Pause/Resume/Cancel runs
Audit & Safety
Every replay run must be auditable:
ReplayRun metadata: start time, operator, filters, transform script, status (Running, Paused, Cancelled, Completed), processed count
Error logs and failure handling per-event
Checkpoints for resume
Event Replay Flowchart
Start
|
v
Create ReplayRun (filters, mode, operator)
|
v
Validate Filters & Acquire Isolation Token
|
v
Open Dedicated Replay Consumer (read-only)
|
v
For each Event in stream (matching filter):
|
+--> If Event already processed (dedupe) -> skip
|
+--> Map/Transform Event (if required)
|
+--> Execute Handler in Replay Mode
- If side-effects allowed? route to sandbox
- Else suppress and log
|
+--> Write to Replay Sink (or Dry Run result)
|
+--> Commit checkpoint
|
v
End Loop
|
v
Mark ReplayRun Completed
|
v
End
Data Models
ReplayRun Table (SQL)
CREATE TABLE ReplayRun (
ReplayRunId UNIQUEIDENTIFIER PRIMARY KEY,
CreatedBy NVARCHAR(200),
CreatedAt DATETIME2,
StreamName NVARCHAR(200) NULL,
FromOffset BIGINT NULL,
ToOffset BIGINT NULL,
FromTime DATETIME2 NULL,
ToTime DATETIME2 NULL,
Mode NVARCHAR(20) NOT NULL, -- DryRun | Replay | ReplayWithSideEffects
Status NVARCHAR(20) NOT NULL, -- Created | Running | Paused | Cancelled | Completed | Failed
ProcessedCount BIGINT DEFAULT 0,
ErrorCount BIGINT DEFAULT 0,
LastCheckpoint BIGINT NULL,
ConfigJson NVARCHAR(MAX) NULL
);
ReplayEventLog (for dedupe & audit)
CREATE TABLE ReplayEventLog (
Id BIGINT IDENTITY PRIMARY KEY,
ReplayRunId UNIQUEIDENTIFIER,
EventId UNIQUEIDENTIFIER,
StreamOffset BIGINT,
EventType NVARCHAR(200),
ProcessedAt DATETIME2,
Outcome NVARCHAR(20), -- Success | Skipped | Error
Details NVARCHAR(MAX)
);
CREATE UNIQUE INDEX UX_ReplayEventLog_Run_Event ON ReplayEventLog(ReplayRunId, EventId);
Replay Worker Design (.NET)
Responsibilities
Create and manage partitions of work (ranges or time windows)
Respect concurrency and ordering where necessary
Use checkpointing per partition for resume
Support backoff and failure retry policies
Emit metrics and progress to Control API
Worker Components
ReplayCoordinator— orchestrates runs, splits workload toPartitionWorkersPartitionWorker— reads events from event store for assigned offsets/time-rangeEventTransformer— applies schema migrations or mapping rulesReplayHandler— executes business logic in replay context (calls projections)SideEffectAdapter— routes side-effect calls to sandbox or suppression loggerCheckpointStore— persist per-partition checkpoints

Join the conversation! Your thoughts help the community grow.