Seconds and Months

A medium 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
medium
Seniority
mid
Asked in
Autodesk

Problem

Design the pipeline that serves concurrent-seat enforcement, monthly metered-usage billing and daily feature-adoption reports from one telemetry stream. Every desktop and browser session of our design and engineering software feeds that stream, about 2 billion events a day.

Business requirements

Worked solution and explanation

Why this problem exists in real interviews

One firehose of telemetry, two consumers with opposite correctness budgets. Licensing wants seat counts within seconds and is happy with approximate as long as it converges; finance wants every metered event counted once and does not care if the number lands a day later. The trap is picking a single clock: stream everything and you pay streaming-scale cost for a billing job that had no latency requirement, or batch everything and licensing enforces seats on yesterday's data. The interviewer is watching whether you justify the path per consumer instead of reaching for one default.

The naive design aggregates all 2 billion daily events in one streaming job that writes a single 'usage' table both consumers read. Licensing is happy. Then a producer retries during a deploy, an offset replays, and the same billable event is summed twice; finance sends an invoice a customer disputes. Meanwhile the streaming bill is several times what it needed to be because the daily adoption report is riding the real-time path for no reason.


Break down the requirements

Step 1: Pin the latency budget per consumer

Licensing is 'within seconds' and tolerates approximate-but-converging counts. Billing is monthly with daily reconciliation and demands exactness. Adoption reporting is daily and demands correctness, not freshness. Write those three budgets down before drawing anything: they decide which path each consumer lives on, and they are the justification the interviewer is grading.

Step 2: Fan out one ingest, do not collect twice

Both paths read the same durable queue. The stream processor consumes it continuously for licensing; the batch path reads the same topic on a daily schedule for finance and product. A second collection path for finance is duplicated operational surface and a place for the two consumers to silently disagree on what happened.

Step 3: Make billing exactly-once at the sink, not in hope

Each event carries a stable client-assigned event_id. The billing job drops every repeat of an event_id before it sums, so a producer retry or a replayed Kafka offset cannot double-count. Anchor the billable period to the event timestamp, not arrival time, so a desktop session that flushes hours late still bills once and into the month it actually happened.


The reference architecture

One Kafka intake fans out. Flink feeds a Redis serving store for seat enforcement; Spark drops repeat `event_id`s for billing and builds daily adoption data, both landing in the warehouse.
  • telemetry_ingest (source, Kafka)
  • stream_processor (transform, Flink); freshness: real-time
  • license_serving_store (storage, Redis)
  • seat_enforcement_service (consumer, API)
  • billing_dedup (transform, Spark)
  • batch_aggregation (transform, Spark); freshness: < 24h
  • analytics_warehouse (storage, warehouse)
  • invoicing_and_adoption_reports (consumer)
  • telemetry_ingest -> stream_processor
  • stream_processor -> license_serving_store
  • license_serving_store -> seat_enforcement_service
  • telemetry_ingest -> billing_dedup
  • billing_dedup -> analytics_warehouse
  • telemetry_ingest -> batch_aggregation
  • batch_aggregation -> analytics_warehouse
  • analytics_warehouse -> invoicing_and_adoption_reports

The split is the whole answer: licensing gets a streaming path into a key-value serving store it queries at seat-check time, and finance plus product get daily Spark jobs into the warehouse. Both read the one Kafka topic, so there is a single source of truth and a single collection cost. The billing dedup is the only place exactly-once machinery lives, because billing is the only consumer that contractually needs it.

Stream everything
One always-on job aggregates all 2B events for every consumer. Simple topology, but you pay real-time compute for daily reporting, and a replayed offset double-bills because there is no dedup boundary.
Path per consumer
Streaming carries only licensing; billing and reporting run daily, with billing deduplicated on event_id. More moving parts, but each consumer is served at its real cadence and billing is exactly-once by construction.

Common follow-up questions