Counted Once, Remembered Forever

A hard Pipeline Design interview practice problem on DataDriven. Design the pipeline on the canvas: sources, transforms, storage and checks, then get feedback on it.

Domain
Pipeline Design
Difficulty
hard
Seniority
mid
Asked in
Fidelity

Problem

A retail brokerage executes about 50 million trades a day across 12 million accounts, and the same execution events feed two consumers: the risk desk's intraday account positions and the end-of-day regulatory filing. Design the pipeline that serves both.

Business requirements

Worked solution and explanation

This is one execution stream serving two consumers with opposite correctness budgets, dressed up as a brokerage pipeline. Risk wants positions in seconds and tolerates a briefly wrong number. Compliance wants every trade counted once and a past filing you can rebuild byte for byte. Anyone can draw a stream into a positions table. The trap is reading the regulatory report off that same mutable table. A producer retry then counts a trade twice, and when an auditor asks what you filed in March, the state has been overwritten a hundred times and there is nothing to replay.

Walk the requirements

Step 1: Fork one durable stream into two independent readers

Executions land once in a durable queue. The streaming job and the archive writer each read it at their own pace, so a slow report run never starves risk and a streaming hiccup never delays the filing. Key the topic by account so per-account fills stay ordered, since positions depend on sequence.

Step 2: Serve risk from a live position store

Flink folds each fill into account state and writes an intraday store that the exposure breach dashboard reads. At-least-once is fine here: a duplicated fill nudges a position and the next event corrects it. What matters is that a breach shows up within seconds, while the market is open and the desk can still freeze the account. Forcing exactly-once here buys latency that risk cannot afford.

Step 3: Compute the filing as a deduped batch over the archive

The end-of-day Spark job reads that day's partition of the immutable archive, drops duplicates on execution_id, and lands the aggregate in a warehouse. Exactly-once lives in the dedup, not in a hope that the stream never repeated itself. The input is immutable and the logic is deterministic, so rerunning the same day next year yields the identical report.

One stream forks: a live path to the exposure breach dashboard, and an append-only archive feeding a deduped daily batch for the filing. The report replays from the archive, never from `intraday_positions`.
  • execution_ingest (source, Kafka)
  • event_archive (storage, object storage)
  • position_stream (transform, Flink); freshness: real-time
  • intraday_positions (storage, Cassandra)
  • exposure_breach_dashboard (consumer)
  • eod_dedup_batch (transform, Spark); freshness: < 24h
  • regulatory_warehouse (storage, warehouse)
  • regulatory_report (consumer)
  • execution_ingest -> event_archive
  • execution_ingest -> position_stream
  • position_stream -> intraday_positions
  • intraday_positions -> exposure_breach_dashboard
  • event_archive -> eod_dedup_batch
  • eod_dedup_batch -> regulatory_warehouse
  • regulatory_warehouse -> regulatory_report

Common follow-up questions