Window a stream correctly — watermarks, dedupe, and late data
Stream processing in practice: start from the kafka-streaming template, pick event-time over processing-time windows, set a watermark you can defend, and prove what happens to late data. Checkpointing and an idempotent MERGE sink make the job restartable without duplicating output.
At a glance
| When | Aggregations over event streams — counts and sums per window; A streaming job that must survive restarts without duplicating output |
|---|---|
| Where | Streaming |
| Why | Windows turn infinite streams into finite, mergeable results — get the watermark wrong and you either drop late data silently or never emit. |
Learning objectives
- Choose event-time vs processing-time windows
- Set a watermark and reason about late data
- Run a structured-streaming job with checkpointing and an idempotent MERGE sink
What you need
- The kafka-streaming template (checkpointing, watermarking, a dedupe stage, an idempotent MERGE sink)
- [object Object]
- A Kafka topic whose events carry an event timestamp and an event_id
Steps
- Start from the template — a structured-streaming job with checkpointing, watermarking, a dedupe stage and an idempotent MERGE sink to Delta/Iceberg. (from tpl-kafka-streaming )
- Decide time semantics first — choose event-time vs processing-time windows. (from project-kafka-spark-delta )
- Follow the reference architecture — Spark SS with watermark 2m and dedupe on event_id, raw_events appended to bronze, agg_5min as a windowed MERGE on the window key. (from project-kafka-spark-delta )
- Read with `startingOffsets=earliest` in dev only; latest in prod. (from project-kafka-spark-delta )
- Dedupe on `event_id` within the watermark; windowed aggregation to 5-minute tumbling windows, appended idempotently. (from project-kafka-spark-delta )
- Prove late-data behavior in tests — a late event beyond the watermark is dropped (documented, not silent), and replaying a batch yields the same aggregate. (from project-kafka-spark-delta )
- Watch the two classic failures — watermark too short means late data silently dropped; checkpoint lost means duplicates, fixed by making the sink idempotent. (from project-kafka-spark-delta )
Check yourself
- An event arriving inside the 2-minute watermark joins its window; one beyond it is dropped — documented in the tests, not silent.
- Replaying a batch yields the same aggregate because the MERGE is on the window key.
Worked example
Bring up the stack and produce events — from project-kafka-spark-delta
make up
make produce # emits events, some deliberately late
make stream &
Implementation rules — from project-kafka-spark-delta
- Read with `startingOffsets=earliest` in dev only; latest in prod.
- Dedupe on `event_id` within the watermark.
- Windowed aggregation to 5-minute tumbling windows, appended idempotently.
- MERGE aggregates on the window key so replays converge.
The reference architecture — from project-kafka-spark-delta
Kafka (events) ─▶ Spark SS [watermark 2m, dedupe on event_id]
├─▶ Delta: raw_events (append, bronze)
└─▶ Delta: agg_5min (windowed, MERGE on window key)
Sourced from
Security scan
Last sweep 2026-10-24: 0 finding(s), 0 marked as examples.
Common gotchas
- Watermark too short → late data silently dropped.
- Read with `startingOffsets=earliest` in dev only; latest in prod.
- Skewed key → one partition saturates; re-key.
Production considerations
- Checkpoints on durable storage with lineage.
- Lag + batch-duration metrics; alert on rising batch duration.
Diagram
windowed streaming job
|
|- Kafka events (event_id, event time)
|
|- watermark 2m --> dedupe on event_id
|
|- 5-minute tumbling windows --> aggregate
|
|- raw_events --> append (bronze)
|- agg_5min --> MERGE on window key (idempotent)
|
--> checkpoint on durable storage; alert on rising batch duration
Registry stats
| Verification | community · Oct 21, 2026 |
|---|---|
| Completeness | 81 |
| Trust multiplier | ×1.25 |
| Composite | 34.15 · adequate |
| Freshness | 3 days since last source check |
| Difficulty | intermediate |
| Version | 0.1.0 |
| License | CC-BY-4.0 |
| Security flags | none |
Did this solve your problem?
Window a stream correctly — watermarks, dedupe, and late data