Batch vs stream processing: now or later?

Your live score updates within a second of every ball; tomorrow's newspaper has the full scorecard. Both come from the same data, processed in two different ways. This lesson shows when to use batch and when to use stream processing, how windows turn an endless stream into answers, and how real systems deal with events that arrive late.

Module 4 · The Ecosystem⏱ 28 minBeginner → AdvancedRuns in your browser (Python)3 real-time scenariosLive stream on your PC9 practice problems
1 The story

Final over: the live score and tomorrow's newspaper

It's the T20 final. Riya is watching the live score on her phone: every ball updates within a second. Kabir's father prefers the newspaper: tomorrow morning he will read the complete scorecard, every batter's strike rate and a chart of where the runs came from. Same match, same data, two completely different ways of processing it.

every ball = one event 6 1 1 W 4 … STREAM BATCH Live score app 178/4 (19.3) updated 0.4 s after each ball Overnight job all 240 balls processed together runs at 1 am, after the match THE MORNING TIMES full scorecard · strike rates · wagon wheel Fast, approximate, one number at a time ↖ Stream: answer now, as each event arrives. Batch: answer later, from all the data at once.
Riya

Sir, my app showed the six before the TV commentator finished shouting!

Arjun Sir

Because your app is fed by a stream: each ball becomes an event, and the system updates the score the moment it arrives. The newspaper uses batch processing: wait for the whole match, then compute everything at once.

Kabir

At TiffinGo our sales report is batch, at 2 am. But the kitchen-overload alert was a stream. How do we decide which one to use?

Arjun Sir

Ask one question: how old can the answer be before it becomes useless? A fraud alert one day late is useless. A monthly salary report computed in one second is pointless.

Riya

So stream is better because it's faster?

Arjun Sir

Faster, but harder and costlier, Riya. Today you'll see why, by processing the same data both ways, watching a stolen phone get stopped in real time, and learning what happens when an event arrives late from a train in a tunnel.

2 Definition

What are batch and stream processing?

Formal definition (write this in exams)

Batch processing processes a bounded, finite set of data that has been collected over a period, usually on a schedule, producing results with high throughput but high latency (minutes to hours). Stream processing processes unbounded data continuously, event by event (or in very small micro-batches) as it arrives, producing results with low latency (milliseconds to seconds). Stream processors typically group events into windows and keep state between events.

In simple words

Batch: collect everything first, then process it in one go, like doing a week's laundry on Sunday. Stream: process each item the moment it arrives, like washing each cup as soon as you finish your tea.

Words you'll meet in this lesson

Bounded dataData with a start and an end: yesterday's orders, last month's payments.
Unbounded dataData that never ends: clicks, payments, GPS pings, sensor readings.
LatencyHow long after an event its result is available.
ThroughputHow many events are processed per second.
WindowA slice of a stream to calculate over: “runs in this over”, “orders in the last 5 minutes”.
StateWhat a stream processor remembers between events: running totals, recent payments of a card.
Event timeWhen something actually happened (the ball was bowled).
Processing timeWhen the system received or processed it, which can be later.
Micro-batchProcessing a stream in tiny batches every few seconds, as Spark Structured Streaming does by default.

Batch and stream at a glance

BatchBounded data · scheduled (hourly, nightly) · latency minutes–hours · simpler, cheaper, easy to re-run · Spark, Hive, MapReduce, dbt
StreamUnbounded data · always running · latency milliseconds–seconds · needs state, windows, late-data handling · Flink, Kafka Streams, Spark Structured Streaming

Batch vs stream at three levels

Pick your level. New to this? Start at Beginner and climb.

Beginner Bucket vs tap

Batch is filling a bucket and carrying it once: efficient, but you wait. Stream is drinking straight from the tap: instant, but the tap must always be running.

  • Batch examples: salary credited on the 1st, electricity bill each month, college result after all papers are checked, the morning sales report.
  • Stream examples: live cricket score, UPI fraud check before money leaves, OTP delivery, a cab's live location on the map.

The one question: how old can the answer be before it is useless? Seconds → stream. Hours or days → batch.

Intermediate Latency, throughput and windows

  • Trade-off: batch maximises throughput and simplicity; stream minimises latency but runs 24×7 and is harder to build and test.
  • Windows turn an endless stream into finite groups: tumbling (fixed, non-overlapping: runs per over), sliding (overlapping: orders in the last 5 minutes, updated every minute) and session (a user's activity until a 30-minute gap).
  • Event time vs processing time: a payment made at 10:00:00 may reach the system at 10:00:05, or later. Correct results group by event time.
  • Micro-batch vs true streaming: Spark Structured Streaming processes small batches every few seconds (or less); Flink processes each event as it arrives. Both are “streaming” for most business needs.
  • Tools: batch with Spark/Hive/dbt scheduled by Airflow; streams with Kafka plus Flink, Kafka Streams or Spark Structured Streaming.

Advanced Late data, guarantees and state

  • Out-of-order and late events are normal (phones offline, network retries). A watermark tells the processor “I believe all events up to time T have arrived”; windows close at the watermark, and an allowed lateness policy decides what happens to events that come after: update the result, send to a side output, or drop.
  • Delivery guarantees: at-most-once (may lose events), at-least-once (may duplicate), exactly-once (each event affects the result once), achieved with checkpointed state plus idempotent or transactional sinks.
  • State and checkpoints: running totals and per-card histories live in a state store that is periodically checkpointed, so a crashed job resumes without losing or double-counting.
  • Backpressure: when a downstream step is slow, the stream must slow the input instead of running out of memory.
  • Reprocessing: fixing a bug in a stream job means replaying old events from Kafka or the lake. This leads directly to the Lambda and Kappa architectures (Lesson 4.4).

Exam tip: Compare batch and stream in a table on data (bounded/unbounded), latency, throughput, processing trigger, complexity, examples and tools. Add the three window types with one example each. That covers most 5- and 10-mark questions.

3 Types and ways to use it

Three processing styles, three window types

BatchMicro-batchStream (event at a time)
InputA day's or hour's filesEvents collected for a few secondsEach event as it arrives
LatencyMinutes to hoursAround a second to several secondsMilliseconds
Typical toolsSpark, Hive, dbt, MapReduceSpark Structured StreamingFlink, Kafka Streams
Good forReports, billing, model training, backfillsNear-real-time dashboards, ETL from KafkaFraud checks, alerts, live tracking
Running costOnly while the job runsAlways onAlways on
Fixing mistakesRe-run the jobReplay from KafkaReplay from Kafka; manage state carefully

Window types

Tumbling window

Fixed size, no overlap, every event in exactly one window. Runs per over, orders per minute, sales per day.

Fixed buckets

Sliding window

Fixed size, moves forward in small steps, so windows overlap. Payments in the last 2 minutes, checked every 10 seconds.

Moving view

Session window

Grows while events keep coming and closes after a gap of inactivity. One shopping visit ends after 30 minutes idle.

Activity-based

Delivery guarantees

GuaranteeWhat can go wrongAcceptable for
At-most-onceSome events are lostApproximate metrics, e.g. page-view counters
At-least-onceSome events are counted twiceMost pipelines, if results are de-duplicated
Exactly-onceNothing, but it costs more effort and some speedPayments, billing, balances

Don't stream what nobody reads in real time. A daily report built on a 24×7 stream costs more and breaks more often than a nightly batch job. Choose stream only when a late answer loses money, safety or customers.

4 Step by step

A UPI payment's fraud check, in under a second

  1. The payment event arrives

    {"txn": "T88214", "payer": "aman@okbank", "amount": 4900,
     "device": "new-android-7f", "city": "Kolkata", "event_time": "10:02:11"}
    The bank's app publishes the event to a Kafka topic before the money moves. The stream processor reads it within milliseconds.
  2. Look up state for this payer

    usual_city = "Pune"; known_devices = {"iphone-12a"}
    recent_payments = [("10:00:40", 4900), ("10:01:05", 4900), ("10:01:31", 4900), ("10:01:50", 4900)]
    The processor keeps state per payer: usual city, known devices and the last few minutes of payments. This lives in the processor's state store, not in a slow database call.
  3. Apply a sliding-window rule

    device, city = "new-android-7f", "Kolkata"     # from the new event
    in_last_2_min = [p for p in recent_payments if p[0] >= "10:00:11"]
    suspicious = len(in_last_2_min) >= 4 and device not in known_devices and city != usual_city
    print(suspicious)
    True
    Five payments of ₹4,900 within two minutes, from a new phone, in a city 1,600 km from usual. A sliding window of 2 minutes catches it.
  4. Decide and respond

    The payment is put on hold and the customer gets a call: “Did you make these payments?”

    The whole check took about 80 milliseconds. A batch fraud report tomorrow morning would have found the same pattern, after the money was gone.
  5. Batch still has a job

    The same events are also written to the lake.

    Every night a batch job uses months of history to retrain the fraud model and tune the rules. Stream makes the decision; batch makes the decision-maker smarter. Most real systems use both.
5 See it happen

The same overs, processed as a stream and as a batch

Step through the six frames. Left: Riya's phone, then the newspaper. Right: the stream processor during the match, and the batch job after it.

Stream now, batch later 6 steps
What you see ● LIVE 6/0 0.1 overs 6 SIX! first ball 10/1 1.2 overs W WICKET! caught 19/1 2.0 overs This over 10 runs 28/1 2.6 overs Score jumped by 6 at once? A delayed ball update just arrived. THE MORNING TIMES Full scorecard Over 1 9 runsOver 2 10 runs 1 wktOver 3 9 runs Run rate 9.33 · Boundaries 3 wagon wheel Live gave speed. The paper gave depth.Both used exactly the same ball events. myphatshala.in
Behind the screen Kafka topic: balls … one event per ball, in order of arrival Stream processor · STATE total = 0 + 6 = 6wickets = 0over 1 = 6 event in → stateupdated → pushedto phones in~0.4 s total = 10wickets = 0 + 1 = 1over 2 = 1 The processoronly remembers afew numbers, notevery past ball. total = 19wickets = 1window "over 2" CLOSED→ emit 10 runs A tumbling windowof 6 balls: eachball belongs toexactly one over. arrived: 2.5, 2.6, then 2.4event time of 2.4 < 2.6→ out of order!placed in over 3 byits EVENT time ✓ Ordering by arrivaltime would be wrong.Watermarks decide howlong to wait. lake: balls/date=2026-10-19/ (complete, bounded) all 240 events, nothing more will arrive 01:00 · Spark batch job • runs per over, per batter, per bowler• strike rates, partnerships, wagon wheel• joins player profiles from another table• can be re-run if a correction comes in Stream: ~0.4 sunbounded · few numbers Batch: ~6 hoursbounded · every detail myphatshala.in
6 Real-world use

Real-time scenarios where the choice matters

Three live scenarios: one where only streaming saves the day, one that shows the three window types on a real timeline, and an advanced one about events that arrive late.

Real-time scenario 1

A stolen phone: stream stops it, batch reports it

Aman's phone is stolen in a crowded market. The thief starts sending UPI payments of ₹4,900 every 20–30 seconds. Watch the stream processor's 2-minute sliding window, and compare with a nightly batch check.

Fraud check per payment 5 steps
Animated example 10:0010:0110:0210:03 ₹4,900 sliding window: last 2 minutes 10:00:40 · payment 1 · known city? no · new phone? yes1 payment in window → allowed (one odd payment isn't fraud)decision in 80 ms 10:01:50 · 4 payments in 2 minutesrisk score rising: same amount, new device, far citystill under the threshold 10:02:11 · 5th payment → RULE FIRES≥ 4 recent payments + new device + unusual citypayment held, account frozen, customer called 10:02:35 · 6th attempt blockedloss stopped at ₹19,600 instead of the full balancethe window keeps sliding every few seconds Nightly batch check at 02:00 next daywould find the same pattern 16 hours laterby then the whole account could be empty Rule (illustrative): ≥ 4 payments in 2 min + new device + unusual city. myphatshala.in
Real-time scenario 2

One timeline, three windows

The same food orders from one office building between 13:00 and 13:40. Watch how tumbling, sliding and session windows group them differently, and why each answers a different business question.

Tumbling, sliding, session 5 steps
Animated example 13:0013:1013:2013:3013:40 10 orders arrive between 13:00 and 13:40 4402 TUMBLING · 10-minute buckets, no overlaporders per 10 min: 4, 4, 0, 2 · every order counted onceuse for: reports per minute/hour/day, runs per over SLIDING · last 20 minutes, moved every 5 minuteswindows overlap; one order is counted in several windowsuse for: “too many in the last N minutes” alerts, moving averages gap > 10 min → session ends SESSION · grows until 10 minutes of silence2 sessions: the lunch rush (8 orders) and a late pair (2)use for: user visits, shopping sessions, a rider's trip Tumbling“How many orders each 10 minutes?” Sliding“Is this building busy right now?” Session“How long is one lunch rush?” Same 10 events, three different questions. myphatshala.in
Real-time scenario 3 · Advanced

The order from the tunnel: late data and watermarks

A passenger on a local train orders food at 18:58, just as the train enters a tunnel. The phone stays offline for 4 minutes and the event reaches the system at 19:02. Which minute should it count in, and how long should the system wait?

Event time, processing time, watermark 5 steps
Animated example 18:5518:5819:0019:0219:04 window 18:55–19:00 ordered 18:58 in the tunnel…phone offline, event not sent 19:02 · event arrives: event time 18:58, processing time 19:02grouped by processing time it lands in the WRONG window→ always group by event time watermark 18:59watermark passes 19:00 → close Watermark = latest event time seen − 3 minutes“I assume nothing older than this is still on its way.”the window stays open until the watermark passes 19:00 Late event arrived before the watermark → counted ✓window 18:55–19:00 closes with 4 orders, not 3cost: this result is published ~3 minutes later The trade-off you choose: short wait (1 min) → fast results, more late events missedlong wait (10 min) → complete results, slower dashboardsevents later than the watermark → update, side table, or drop A nightly batch job can always correct the totals afterwards. myphatshala.in

Which one do real companies use?

ticks

1. Stock market: stream

Price ticks arrive many times per second. Trading platforms update charts, trigger stop-loss orders and run risk checks on the stream. End-of-day settlement and tax reports are batch.

Price ticks→Stream: alerts, stop-loss→Batch: EOD reports
₹ 1st

2. Payroll: batch

Salaries are computed once a month from attendance, leave and tax data. Nobody needs them every second; correctness and an audit trail matter far more. A scheduled batch job is the right tool.

Monthly attendance→Batch job on the 28th→Salary on the 1st

3. Factory sensors: stream

Machines report temperature and vibration every second. A stream job raises an alert when readings stay above a limit for 30 seconds, before a breakdown. Weekly maintenance planning runs as batch on the same data.

Sensor readings→Sliding-window alert→Stop the machine
● 2.3 crwatching now

4. Live streaming apps: both

The “watching now” counter and buffering alerts come from a stream of player heartbeats. Royalty payments and next-day “top shows” lists come from batch jobs over the complete data.

Player heartbeats→Stream counter + batch reports→Live number + reports

5. Online ads: stream for spend, batch for bills

Click events are streamed so a campaign stops spending the moment its daily budget is used. Advertisers' monthly invoices are computed in batch after de-duplicating and removing fraudulent clicks.

Ad clicks→Stream: budget cap · Batch: invoice→Accurate bill

Examples are simplified; real systems combine both styles. Rules and numbers shown are illustrative.

7 Run the code

The same orders, processed two ways

Six orders arrive during the day. The stream job updates its answer with every event; the batch job waits for the complete list and answers once. Compare when each answer is available. Then try windows, a fraud rule, late events and duplicates in the challenges.

orders = [  # (minute, kitchen, amount)
    (1, "K12", 120), (1, "K11", 90), (2, "K12", 250),
    (3, "K12", 180), (3, "K13", 60), (4, "K12", 140),
]

# STREAM: update the answer as each event arrives
def stream_job(events):
    total = 0
    for minute, kitchen, amount in events:
        total = total + amount
        print(f"[stream  @ minute {minute}] +{amount:>3} from {kitchen} -> running total Rs {total}")

# BATCH: wait until all data is collected, then process it in one go
def batch_job(all_orders):
    total = sum(amount for _, _, amount in all_orders)
    busiest = max(set(k for _, k, _ in all_orders),
                  key=lambda k: sum(a for _, kk, a in all_orders if kk == k))
    print(f"[batch   @ end of day] {len(all_orders)} orders, Rs {total}, busiest kitchen {busiest}")

stream_job(orders)
batch_job(orders)
[stream @ minute 1] +120 from K12 -> running total Rs 120 [stream @ minute 1] + 90 from K11 -> running total Rs 210 [stream @ minute 2] +250 from K12 -> running total Rs 460 [stream @ minute 3] +180 from K12 -> running total Rs 640 [stream @ minute 3] + 60 from K13 -> running total Rs 700 [stream @ minute 4] +140 from K12 -> running total Rs 840 [batch @ end of day] 6 orders, Rs 840, busiest kitchen K12
  • for minute, kitchen, amount in events:The stream job never sees “all” the data. It handles one event, updates its state (total) and moves on.
  • print(f"[stream @ minute {minute}] ...An answer is available after every event: low latency.
  • total = sum(amount for _, _, amount in all_orders)The batch job has the complete, bounded data, so it can answer harder questions in one pass, like “which kitchen was busiest overall?”

Run it on your PC: a live score stream in your terminal

This program generates a “live” ball every 0.3 seconds and processes it as a stream: the score updates immediately, and a 6-ball tumbling window closes at the end of every over. After the last ball it prints a batch summary computed from the complete data. Save it as live_score.py and watch it scroll.

Watch a stream being processed

import random, time

random.seed(27)
OUTCOMES = [0, 0, 1, 1, 1, 2, 4, 6, "W"]


def ball_stream(overs=3):
    """An endless-looking stream of balls, one every 0.3 s (sped up)."""
    for over in range(1, overs + 1):
        for ball in range(1, 7):
            time.sleep(0.3)
            yield over, ball, random.choice(OUTCOMES)


# STREAM processing: update the answer the moment each ball arrives
total, wickets, over_runs, per_over = 0, 0, 0, []
start = time.time()
for over, ball, result in ball_stream():
    if result == "W":
        wickets += 1
    else:
        total += result
        over_runs += result
    print(f"{time.time() - start:4.1f}s  ball {over - 1}.{ball}  {str(result):>2}   score {total}/{wickets}")
    if ball == 6:                       # the "over" window closes
        print(f"        --- over {over}: {over_runs} runs ---")
        per_over.append(over_runs)
        over_runs = 0

# BATCH processing: after the match, compute from the complete data
print("Batch summary after the match:", per_over, "| run rate", round(total / len(per_over), 2))

# In a terminal:  python live_score.py
0.3s ball 0.1 6 score 6/0 0.6s ball 0.2 1 score 7/0 0.9s ball 0.3 1 score 8/0 1.2s ball 0.4 1 score 9/0 1.5s ball 0.5 0 score 9/0 1.8s ball 0.6 0 score 9/0 --- over 1: 9 runs --- 2.1s ball 1.1 1 score 10/0 2.4s ball 1.2 W score 10/1 2.7s ball 1.3 2 score 12/1 3.0s ball 1.4 1 score 13/1 3.3s ball 1.5 2 score 15/1 3.6s ball 1.6 4 score 19/1 --- over 2: 10 runs --- 3.9s ball 2.1 1 score 20/1 4.2s ball 2.2 1 score 21/1 4.5s ball 2.3 1 score 22/1 4.8s ball 2.4 6 score 28/1 5.1s ball 2.5 0 score 28/1 5.4s ball 2.6 0 score 28/1 --- over 3: 9 runs --- Batch summary after the match: [9, 10, 9] | run rate 9.33

Recorded from a real run. The balls are the same every time (the random generator is seeded); the timings in the first column will differ slightly on your computer. Notice that each line appears 0.3 s after the previous one, as a real stream would, while the batch summary appears only at the very end.

8 Line by line

A tumbling window, one event at a time

Orders arrive with the minute they happened. The stream job keeps a running total for the current minute; when an event from a new minute arrives, the old window closes and its result is printed. Watch window and total in the frame.

Worked examples: real problems, solved and traced in memory

Four problems from first-week analyst to streaming engineer. Each runs live and is traced line by line.

Example 1BeginnerProduct team · design choice

Batch or stream? Decide from the deadline

Problem statement

For each use case, the business says how old the answer may be (in seconds) before it becomes useless. Classify each: under 60 seconds → stream; otherwise → batch.

Input
fraud check 1 s · live score 2 s · salary 86400 s · monthly bill 604800 s · surge price 30 s · sales report 21600 s
Expected output
fraud check   STREAM
live score    STREAM
salary        batch
monthly bill  batch
surge price   STREAM
sales report  batch

Approach

  1. Store each use case with its maximum acceptable age.
  2. Loop over them and compare with 60 seconds.
  3. Print the choice.

Solution: run it live

What happens in memory, step by step

Recorded from a real Python run: press Next to execute one line at a time. Watch variables change in each frame, and lists and dictionaries (numbered #1, #2 …) fill up as objects.

Example 2IntermediateSports app · tumbling window

Runs per over from ball-by-ball events

Problem statement

A sports app receives one event per ball. Produce the runs in each over (a 6-ball tumbling window) and the over with the most runs.

Input
12 balls: 6,1,1,1,0,0, 1,W,2,1,2,4
Expected output
Runs per over: [9, 10]
Best over: 2

Approach

  1. Walk through the balls, adding runs (a wicket adds 0).
  2. Every 6th ball, the window closes: save the over's runs and reset.
  3. Find the best over with max.

Solution: run it live

What happens in memory, step by step

Recorded from a real Python run: press Next to execute one line at a time. Watch variables change in each frame, and lists and dictionaries (numbered #1, #2 …) fill up as objects.

Example 3IntermediateBank · sliding window

Flag a card used too often

Problem statement

For each card payment, count how many payments the same card made in the last 60 seconds. Flag any payment where the count exceeds 3.

Input
times (s): 0, 10, 20, 30, 45, 200
Expected output
0 1 ok
10 2 ok
20 3 ok
30 4 FLAG
45 5 FLAG
200 1 ok

Approach

  1. Keep a list of recent payment times for the card.
  2. For each new payment, drop times older than 60 s, then add the new one.
  3. Flag if the list is longer than 3.

Solution: run it live

What happens in memory, step by step

Recorded from a real Python run: press Next to execute one line at a time. Watch variables change in each frame, and lists and dictionaries (numbered #1, #2 …) fill up as objects.

Example 4AdvancedStreaming engineer · late data

Count orders per 10-minute window with a watermark

Problem statement

Order events arrive out of order. Count orders per 10-minute window by event time, using a watermark of “largest event time seen minus 5 minutes”. Events behind the watermark go to a late list.

Input
event times (minute): 1, 4, 12, 8, 15, 3, 22
Expected output
Windows: {0: 3, 10: 2, 20: 1}
Late: [3]

Approach

  1. Track the largest event time seen; the watermark is that minus 5.
  2. If an event is older than the watermark, it is late: keep it aside.
  3. Otherwise add it to its window: (t // 10) * 10.

Solution: run it live

What happens in memory, step by step

Recorded from a real Python run: press Next to execute one line at a time. Watch variables change in each frame, and lists and dictionaries (numbered #1, #2 …) fill up as objects.

9 Quiz and revision

Check yourself

Quick revision

Lesson 4.2 in one screen

  • Batch: bounded data, scheduled, high latency, high throughput, simpler. Stream: unbounded, continuous, low latency, needs state.
  • Decide by: how old can the answer be before it is useless?
  • Windows: tumbling (fixed, no overlap) · sliding (overlapping, recent) · session (ends after a gap).
  • Event time = when it happened; processing time = when it was handled. Group by event time.
  • Watermark = how long to wait for late events; a trade-off between speed and completeness.
  • Guarantees: at-most-once (loss), at-least-once (duplicates), exactly-once (neither).
  • Tools: batch → Spark, Hive, dbt + Airflow · stream → Kafka + Flink, Kafka Streams, Spark Structured Streaming.

Interview and viva questions

Differentiate batch processing and stream processing.

Batch processes a bounded dataset collected over time, on a schedule, with high throughput and latency of minutes to hours (daily reports, billing, model training). Stream processing handles unbounded data continuously as events arrive, with latency of milliseconds to seconds, keeping state and using windows (fraud detection, live dashboards, alerts). Batch is simpler and cheaper; stream is faster but harder to build and operate.

What are windows in stream processing? Explain their types.

Windows divide an endless stream into finite groups for calculation. Tumbling windows are fixed-size and non-overlapping (orders per minute). Sliding windows are fixed-size but overlap, moving forward in small steps (payments in the last 5 minutes, every 30 seconds). Session windows grow with activity and close after a gap of inactivity (a user's visit).

What is the difference between event time and processing time?

Event time is when an event actually occurred, recorded at the source. Processing time is when the system processes it. Network delays and offline devices make them differ, so correct aggregations group by event time and use watermarks to handle late events.

What is a watermark?

A watermark is the stream processor's estimate that all events up to a certain event time have arrived, usually the maximum event time seen minus an allowed delay. When the watermark passes the end of a window, the window is finalised; events arriving later are handled by an allowed-lateness policy.

What is micro-batching?

Processing a stream as a series of very small batches, every few seconds or less, as Spark Structured Streaming does by default. It reuses batch machinery and gives good throughput with near-real-time latency; event-at-a-time engines like Flink can reach lower latency.

Practice problems

Window and latency exercises, from easy to advanced. The last two are business decisions about cost and service levels.

P1Easy

Classify by latency

Print “stream” if the required latency is under 10 seconds, else “batch”, for 2, 3600 and 0.5 seconds.

Input
[2, 3600, 0.5]
Expected output
2 -> stream
3600 -> batch
0.5 -> stream
Show solution and explanation
for need in [2, 3600, 0.5]:
    print(need, "->", "stream" if need < 10 else "batch")
2 -> stream 3600 -> batch 0.5 -> stream

How it works: The required latency decides the style, not the size of the data.

P2Easy

Throughput

A stream processed 9,00,000 events in 5 minutes. Print events per second.

Input
900000 events, 300 s
Expected output
3000.0 events per second
Show solution and explanation
print(900000 / 300, "events per second")
3000.0 events per second

How it works: Throughput = events ÷ seconds.

P3Easy

Hourly batch size

An app produces 2,500 events per second. How many events does one hourly batch contain?

Input
2500 events/s
Expected output
9,000,000 events per hourly batch
Show solution and explanation
print(f"{2500 * 3600:,} events per hourly batch")
9,000,000 events per hourly batch

How it works: Batch size grows with the interval; that is why batch jobs need many machines.

P4Medium

10-minute tumbling windows

Given order minutes, count orders in each 10-minute window (0, 10, 20 …).

Input
[1, 3, 9, 12, 15, 27, 28, 29]
Expected output
{0: 3, 10: 2, 20: 3}
Show solution and explanation
minutes = [1, 3, 9, 12, 15, 27, 28, 29]
counts = {}
for m in minutes:
    w = (m // 10) * 10
    counts[w] = counts.get(w, 0) + 1
print(counts)
{0: 3, 10: 2, 20: 3}

How it works: (m // 10) * 10 maps each minute to the start of its window.

P5Medium

Moving average of 3 readings

For each temperature reading, print the average of the last 3 readings (a sliding window of size 3).

Input
[30, 32, 34, 40, 41]
Expected output
30 -> avg of last 3: 30.0
32 -> avg of last 3: 31.0
34 -> avg of last 3: 32.0
40 -> avg of last 3: 35.3
41 -> avg of last 3: 38.3
Show solution and explanation
temps = [30, 32, 34, 40, 41]
for i in range(len(temps)):
    window = temps[max(0, i - 2):i + 1]
    print(temps[i], "-> avg of last 3:", round(sum(window) / len(window), 1))
30 -> avg of last 3: 30.0 32 -> avg of last 3: 31.0 34 -> avg of last 3: 32.0 40 -> avg of last 3: 35.3 41 -> avg of last 3: 38.3

How it works: Each window overlaps the previous one: a sliding window.

P6Advanced

Count sessions

Click times are given in minutes. A session ends after a gap of more than 20 minutes. Print the number of sessions.

Input
[0, 5, 8, 40, 42, 90]
Expected output
Sessions: 3
Show solution and explanation
clicks = [0, 5, 8, 40, 42, 90]
sessions = 1
for prev, cur in zip(clicks, clicks[1:]):
    if cur - prev > 20:
        sessions = sessions + 1
print("Sessions:", sessions)
Sessions: 3

How it works: Each gap larger than the limit starts a new session window.

P7Advanced

At-least-once to exactly-once

The same event ids may be delivered more than once. Print the number of unique events and how many duplicates were dropped.

Input
[e1, e2, e2, e3, e1, e4]
Expected output
Unique: 4 | duplicates dropped: 2
Show solution and explanation
events = ["e1", "e2", "e2", "e3", "e1", "e4"]
unique = []
for e in events:
    if e not in unique:
        unique.append(e)
print("Unique:", len(unique), "| duplicates dropped:", len(events) - len(unique))
Unique: 4 | duplicates dropped: 2

How it works: De-duplicating by a unique id turns at-least-once delivery into exactly-once results.

P8Business problem

Always-on stream vs nightly batch

A stream job needs 4 nodes running 24 hours a day; a nightly batch needs 20 nodes for 2 hours. A node costs Rs 30 per hour. Print the monthly (30-day) cost of each (illustrative).

Input
Rs 30/node-hour
Expected output
Stream: Rs 86400
Batch : Rs 36000
Show solution and explanation
stream = 4 * 24 * 30 * 30
batch = 20 * 2 * 30 * 30
print("Stream: Rs", stream)
print("Batch : Rs", batch)
Stream: Rs 86400 Batch : Rs 36000

How it works: Streams cost money every hour. Pay for real time only where it creates real value.

P9Business problem

Did we meet the 1-second promise?

The bank promises a fraud decision within 1,000 ms. Given decision times, print the percentage that met the promise.

Input
[80, 95, 120, 1500, 70, 90, 2100, 85]
Expected output
75 % within 1 second
Show solution and explanation
times_ms = [80, 95, 120, 1500, 70, 90, 2100, 85]
ok = sum(1 for t in times_ms if t <= 1000)
print(round(ok / len(times_ms) * 100), "% within 1 second")
75 % within 1 second

How it works: Streaming systems are judged by latency targets (SLAs), usually measured as percentages like this.

Real-world scenario questions (asked in company interviews)

Situations where choosing batch or stream, or handling time correctly, is the real test. Decide your answer first, then open the model answer.

Retail · requirementsFresher

“Make the daily sales report real-time”

A store manager asks for the daily sales report, which is read once each morning, to be built on Kafka and Flink “because real-time is modern”.

The interviewer is checking: do you choose based on the business need, not on fashion?

Show a strong answer

Ask how the report is used. If it is read once at 9 am, an answer at 6 am is as good as one at 8:59:59. A nightly batch job is cheaper, simpler to test and easy to re-run.

  • If the manager actually needs intraday decisions (restocking during a sale), offer an hourly batch or a small live counter for just that metric.
  • Keep stream processing for cases where a late answer loses money or customers.

Avoid: building a 24×7 streaming system for a report nobody reads in real time.

Fintech · fraud1–3 years

Fraud is found the next morning

A wallet company's fraud report runs every night. Losses keep growing because stolen accounts are emptied within minutes. Design the change.

The interviewer is checking: can you design a basic streaming flow with state, windows and a fallback to batch?

Show a strong answer
  1. Publish every payment attempt to Kafka before it is completed.
  2. A stream processor (Flink or Spark Structured Streaming) keeps per-account state: recent payments, known devices, usual location.
  3. Apply rules and a model score over sliding windows (for example, payments in the last 2 minutes) and return allow, hold or block within the latency budget.
  4. Keep the nightly batch job to retrain the model and tune rules on full history.
  5. Monitor latency and false positives; blocking genuine customers has a cost too.

Avoid: running the nightly job every 5 minutes and calling it real time; it still can't stop a payment in progress.

Payments · correctness1–3 years

The live revenue counter is higher than the bank's figure

A streaming dashboard shows ₹1.02 crore for today; the settlement file says ₹1.00 crore. The stream job restarted twice today after crashes.

The interviewer is checking: do you understand delivery guarantees and how restarts cause duplicates?

Show a strong answer

The pipeline is probably at-least-once: after each crash it re-read events since its last checkpoint and counted some twice.

  • Make results idempotent: de-duplicate on transaction id, or write with upserts keyed by id.
  • Use the engine's checkpointing with transactional or idempotent sinks for exactly-once results.
  • Reconcile daily against the settlement file and alert on differences.

Avoid: “fixing” the dashboard by subtracting an estimated difference.

Mobile gaming · late data3+ years

Players' events arrive hours late

A mobile game sends events when the phone is online. Players on flights or in villages with weak signal send events hours later. Hourly “active players” counts keep changing after they are published.

The interviewer is checking: event time, watermarks, allowed lateness and how batch corrects stream results.

Show a strong answer
  • Aggregate by event time (from the phone), not by arrival time.
  • Set a watermark that matches business needs, e.g. 10 minutes, and publish hourly counts as provisional.
  • Send events later than the allowed lateness to a side output instead of dropping them.
  • Run a nightly batch job over the complete data in the lake to publish final numbers. That is the Lambda idea from Lesson 4.4.
  • Guard against wrong device clocks: reject or clamp event times far in the future.

Avoid: waiting hours before showing any number, or silently dropping late events.