Interview conceptSystem Design

Event-Time Telemetry For Unreliable Devices

Asked of: Software Engineer

Last updated

What's being tested

Candidates must show they can design a resilient, event-time-aware telemetry system for intermittently connected devices: define clear APIs, choose stateful streaming semantics, reconcile late or duplicate events, and ensure safe command dispatch with idempotency and auditing. Interviewers probe distributed-state choices, event-time vs processing-time reasoning, tradeoffs between latency and correctness, and concrete failure modes (clock drift, network partitions, device reboots).

Core knowledge

  • Event time vs processing time: event time is the timestamp generated by the device; processing time is when the server sees it. Correct historical metrics require event-time semantics and handling of out-of-order arrivals.

  • Watermarks & allowed lateness: a watermark = max_seen_event_time − lateness_bound (L). Use watermarks to emit windows; keep state for an extra L to accept late arrivals and trigger retractions if needed.

  • Windowing and retention math: if average ingress = R events/sec and allowed lateness = L seconds, expected late-state memory ≈ R * L * average_event_size. Quantify to choose memory vs eviction policies.

  • Idempotency & deduplication: require clients to include monotonic event IDs or (device_id, sequence, device_time); store recent IDs in compacted store (e.g. `RocksDB` or `Postgres`) to dedupe, with TTL based on allowed lateness.

  • Append-only event store + compacted view: persist raw events immutably (for reprocessing/backfill). Maintain a compacted, materialized view for fast reads; rebuild via replay when late events arrive or schema changes.

  • Exactly-once vs at-least-once: prefer at-least-once ingestion with application-level idempotency; exactly-once across distributed components is expensive (2PC, transactions) and often unnecessary for telemetry.

  • Command dispatch semantics: commands need idempotency keys, sequence numbers, and ack semantics (ACK, NACK, UNKNOWN). Use optimistic command TTL and device-side de-dup logic; track per-device last-applied command version.

  • Safety & auditability: for safety-critical control, include immutable audit logs of commands and telemetry, digital signatures or HMACs on device messages, and operator-facing explainability for retracted metrics.

  • Reconciliation & backfills: build scheduled reconciliation jobs to scan raw events, re-evaluate aggregates, and write deltas or retractions into the materialized view; optimize with incremental computation.

  • Stateful stream processing options: `Flink`/`Beam`/`Spark Structured Streaming` offer built-in event-time windows and state with checkpoints; local embedded state (e.g., `RocksDB`) plus checkpointing simplifies recovery.

  • Clock drift and trust model: never blindly trust device clocks; allow device-side monotonic counters or server-assigned ingestion timestamps plus device clocks for ordering. Define behavior when device time differs by >X minutes.

  • Operational SLOs & metrics: monitor `p99` ingestion latency, fraction of late events, dedupe rate, reconciliation lag, and command success/failure rates; these guide tuning of lateness bounds and retention.

Tip: require devices to include both a device-generated timestamp and a sequence number; server uses sequence for ordering and device timestamp for event-time semantics and audits.

Worked example — Design an IoT Logging Platform with Late-Arriving Metrics

Start by clarifying SLAs: acceptable reporting latency, maximum tolerable correction window (allowed lateness L), and scale (devices, events/sec). Organize the design around three pillars: (1) ingestion and durable raw storage (append-only topic + object store or `Postgres`/S3), (2) event-time stream processing that uses watermarks and maintains materialized aggregates with a lateness-bound L, and (3) reconciliation/backfill that replays raw events to correct aggregates and emits retractions or deltas. Define concrete APIs: client PUT includes (device_id, seq, device_ts, payload, signature) and server returns (ingest_id, server_ts). Flag the main tradeoff: larger L increases correctness but requires more state and delays final metrics; choose L from device connectivity patterns (e.g., 1 hour vs 24 hours). Also describe client behavior on network loss (buffer to disk with exponential backoff) and server dedupe using (device_id, seq) plus TTL. Close by noting next steps: implement end-to-end tests with simulated late arrivals, and if time permits add adaptive watermarks (advance faster for stable devices).

A second angle — Design Command Dispatch and Telemetry Reconciliation for Unreliable Devices

Here the same event-time and reconciliation concepts apply, but the system must treat commands as first-class, safety-critical state. Ask whether commands must be guaranteed delivered, executed exactly once, or only best-effort. Build a command ledger (append-only) with per-command idempotency keys and per-device sequence numbers; dispatch through a broker that persists until device ack. Use event-time telemetry to reconcile whether commands had the intended effect—telemetry events should reference the command id. For retries, cap attempts and escalate to human operators if no ack within a time budget. Explicitly surface the tradeoff: strict guarantees (exactly-once execution) require device-side transactional semantics and fencing tokens; most systems accept at-least-once execution plus idempotent handlers and compensating actions.

Common pitfalls

Pitfall: Treating processing-time as equivalent to event-time. Relying on ingestion timestamps produces incorrect historical metrics and incorrect command/telemetry order when devices are offline or clocks drift.

Pitfall: Not specifying client-side guarantees early. Failing to ask whether devices can persist state, include sequence numbers, or sign messages leads to brittle server designs that can't dedupe or verify authenticity.

Pitfall: Over-engineering exactly-once across the entire stack. Proposing distributed two-phase commits or synchronous cross-service transactions wastes time; prefer immutable logs + idempotency and selective transactional boundaries.

Connections

Interviewers may pivot to stream-processing internals (checkpointing, state backends), distributed consensus for leader election/fencing (e.g., `ZooKeeper`/`etcd`), or data-engineering concerns like efficient compaction and schema evolution for the raw event store.

Further reading

  • [“Designing Data-Intensive Applications” — Martin Kleppmann] — chapters on logs, stream processing, and reprocessing explain append-only stores and event-time concepts.

  • Apache Flink: Event Time & Watermarks (blog/documentation) — practical details on watermarks, lateness, and state management.

Practice questions

Related concepts