How Data Moves: Beginner
What you will be able to do
- ▸The boundary: which rows belong to this run, stated as a window such as orders placed on October 18 in UTC.
- ▸The trigger: what starts the run, a clock (02:00 daily) or an upstream event (the export finished).
- ▸The rerun: what happens when the same run executes twice, because at some point it will.
What batch means
Each arrow carries 1 day of orders, selected by the run's date boundary.
Saying the boundary out loud
'Yesterday' means 2 different things to 2 different people. State it as a half-open interval: ordered_at >= '2026-10-18 00:00:00' and ordered_at < '2026-10-19 00:00:00', in UTC. The half-open shape means an order placed at exactly midnight lands in 1 day and never in both, and 2 adjacent runs cover every second without overlap. The query the job runs looks like this:
Before that insert runs, the job deletes any rows already sitting in daily_sales for October 18, and both statements run in 1 transaction, so a crash between them leaves the old rows and no reader sees the day empty or half-written. That pair is what makes the rerun answer correct: run the job once and the day has 1 set of rows, run it 3 times and it still has 1 set. Appending without the delete means a retry doubles revenue for that date, and the interviewer will ask what happens on retry whether you raise it first.
Where the daily job breaks
| Break | What the dashboard shows | Property that prevents it |
|---|---|---|
| Retry after a partial failure | Revenue for the day doubled | Replace the date's rows instead of appending |
| Late data: an order committed at 23:59:58 reaches the extract after the run | Yesterday short by a few orders | Extract from a snapshot taken after a short lag, and allow a rerun for the date |
| Schema change: a column added to orders | The job fails, or `SELECT *` shifts values into the wrong columns | An explicit column list and a row count check against the source |
| Source unavailable at 02:00 | No rows for the date at all | A retry after a wait, then an alert if it still fails before the 06:00 deadline |
The answer that scores
What a stream is
A swipe becomes an event, waits in the log for milliseconds, and reaches a decision before the terminal prints the receipt.
Event time and processing time
| event_id | event_time | arrived_at | Window by event time | Status on arrival |
|---|---|---|---|---|
| evt_101 | 14:02:11 | 14:02:12 | 14:00 to 14:05 | window open, counted |
| evt_102 | 14:04:50 | 14:04:51 | 14:00 to 14:05 | window open, counted |
| evt_103 | 14:03:30 | 14:07:40 | 14:00 to 14:05 | arrives 2 min 40 s after the window ended |
| evt_104 | 14:06:05 | 14:06:06 | 14:05 to 14:10 | window open, counted |
Retry in a stream
Justifying the cost
- Compute that runs around the clock, for an hour of 10 events as much as for an hour of 10 million
- A broker to operate, where someone has to watch retention and partitions as well as consumer positions
- Harder debugging: there's no input file to open and rerun, only a log position
- 2 clocks and late data inside every aggregate
- A decision whose value decays in seconds: a fraud block, an oversold item, a surge price
- An alert that is worthless if it lands an hour late
- A user-facing feature that reflects the user's own last action
- Events that are also written to storage, so batch jobs can reuse them later
The scored version
- ▸Knowing the file is finished uploading before reading it
- ▸Recording which files have been loaded, so a re-delivered file replaces instead of duplicating
- ▸Noticing when a file fails to arrive at all
- ▸Expecting the format to drift: a new column, a changed delimiter, a new date format
- ▸Keeping the raw rows so a bad parse can be redone without asking for the file again
Is the file complete?
Where a partial read happens depends on where the file lands. On an SFTP server or a shared file system, a 400 MB file is visible with 120 MB written, and a loader that starts then reads a truncated file and exits cleanly; the defense there is either a temporary name that the sender renames on completion, or a check that the file's size and modification time haven't changed across 2 polls a minute apart. A cloud bucket lists an object only once its upload completes, so the risk moves up a level: a delivery split across several files can be half-landed, or a file can arrive whole yet truncated because the export behind it failed. There the sender writes a marker last (a _SUCCESS file or a manifest listing names and row counts) and the loader waits for it. The manifest's row count is the only check that catches a complete file missing rows.
The ledger
| file_name | size_bytes | row_count | status | loaded_at |
|---|---|---|---|---|
| settlements_2026-10-16.csv | 18,442,019 | 91,207 | loaded | 2026-10-17 03:12 |
| settlements_2026-10-17.csv | 19,011,882 | 94,660 | loaded | 2026-10-18 03:09 |
| settlements_2026-10-18.csv | 7,320,114 | 36,118 | loaded | 2026-10-19 03:11 |
| settlements_2026-10-18.csv | 19,280,540 | 95,402 | pending |
Inside the file
- Header row: present or absent, and does the loader trust it or a fixed column list?
- Delimiter and quoting: a merchant name containing a comma must be quoted, and the loader must honor the quotes.
- Encoding: UTF-8 is assumed until a name with an accent turns into garbage.
- Dates: 10/11/2026 is October 11 in one country and November 10 in another.
- Empty values: an empty string, the word NULL and a missing field can mean 3 different things.
- Numbers: 1,234.50 and 1.234,50 are the same amount written in 2 locales.
Where file loads break
| Break | Symptom | Property that prevents it |
|---|---|---|
| Loader reads a half-uploaded file | Row count far below normal, no error | Wait for a marker or manifest before reading |
| Same file delivered twice | Every settlement counted twice | Ledger by file name, and rows tagged with source_file |
| File never arrives | Yesterday missing from reports in silence | An expected-by time with an alert when nothing has landed |
| Sender adds a column in the middle | Amounts land in the date column | Load by header name, and reject a file whose headers changed |
| Retry after a crash mid-load | Partial rows plus a full reload | Load into staging, then move into the target in 1 step |
- Tag every row with its source file and load time
- Alert on a late file as well as a failed one
- Compare row counts to the manifest and to the last 7 days
- Keep the original file for 30 days or longer
- Read a file the moment it appears in the bucket
- Trust column position over column name
- Delete the raw file once the load succeeds
- Treat a smaller-than-usual file as a quiet day
The scored version
- ▸Pagination: the API returns 100 records at a time, and the loop has to follow the pages to the end
- ▸Rate limit: a 429 response means wait the requested time before repeating the same call
- ▸Retry: a 500 or a timeout is retried with a growing wait; a 400 is a bug to fix
- ▸Incremental: an updated_since parameter so a daily pull fetches changes, with a small overlap
- ▸Raw first: store the response body as received, then parse it in a second step
Following the pages
What each response means
| Response | Meaning | Action |
|---|---|---|
| 200 | Page returned | Store the raw body, parse, continue |
| 401 | Token expired or wrong | Refresh the token once, then fail loudly |
| 404 | Resource gone | Record it, do not retry |
| 429 | Too many requests | Sleep for Retry-After seconds, then repeat the same call |
| 500, 502, 503 | Vendor side failure | Retry with waits of 2, 4, 8 and 16 seconds, then fail the run |
| Timeout | No answer within 30 s | Treat as a 503: same retry schedule |
Pulling only what changed
Where API pulls break
| Break | Symptom | Property that prevents it |
|---|---|---|
| Run fails on page 1,400 and restarts from page 1 | 140,000 records fetched twice | Table keyed on id, and the last cursor saved so a retry can resume |
| Vendor renames `email` to `email_address` | Nulls in every new row, no error | Raw bodies stored, and a parse step that fails on a missing required field |
| Records inserted during an offset pull | One record missing, 1 duplicated | Cursor pagination, or a full pull on a quiet schedule |
| Token expires in the middle of a run | 401 on every call after minute 60 | Refresh on 401 and retry the same call once |
The scored version
The question to ask back
- Freshness of an hour or more is acceptable
- The consumer is a report, a model training run or an invoice
- The computation needs the whole day to be correct, like a daily total
- Input arrives on a schedule anyway, such as a nightly file
- Correctness and rerunability matter more than speed
- Freshness under a minute changes a decision
- The consumer is a system acting automatically
- The value of each event decays in seconds
- The source already emits events
- The team can operate a broker and an always-on consumer
| Request | Freshness needed | Consumer | Choice | Why |
|---|---|---|---|---|
| Monthly revenue close | 1 day | Finance analysts | Nightly batch | Totals need the full day, and any date must be rerunnable |
| Launch day signups dashboard | 15 min | Product team watching a page | Batch every 15 min | Humans act no faster than that, and no broker is needed |
| Card fraud decision | 2 s | Approval system | Stream | The event's value is gone once the swipe is approved |
| In-stock badge on a product page | 30 s | Web page, millions of visitors | Stream | Overselling costs refunds and trust |
| Nightly model training set | 24 h | Training job | Nightly batch | The job reads a bounded set once |
The middle option
The answer pattern
- Restate the need with a number: 'you want signups within 15 minutes of happening.'
- Name the consumer: 'a product team refreshing a page during launch week.'
- Choose, and tie it to the number: 'a batch every 15 minutes reads the same signup table the nightly job reads.'
- Name the cost of the alternative: 'a stream would need a broker and an always-on consumer for a page nobody refreshes faster.'
- Name where your choice breaks: 'if the ask drops under a minute, I would move signups to a stream.'
- ▸'Real time' with no number attached. Ask for the number; 'real time' has meant anything from 1 second to 1 hour.
- ▸'Streaming is more modern.' Freshness is the requirement, and the age of a technique has no place in the decision.
- ▸Forgetting corrections. A stream computes forward only; say that history gets recomputed by a batch over the stored events.
- ▸Picking batch for an automated action. A system that blocks a card cannot wait for 02:00.
A worked exchange
> A food delivery company's data team runs all 4 flows on a Friday night. Courier GPS pings and order status changes arrive as a stream, because the ETA on the customer's screen loses its value within 30 seconds. At 02:00 a batch job rebuilds restaurant payout totals for the previous UTC day, replacing the day's rows so finance can rerun any date. At 03:00 the payment processor's settlement file lands with a manifest, is compared against the ledger, and is loaded with its file name on every row. Every 10 minutes a job pages through a weather vendor's API with a cursor, waiting on 429, to feed tomorrow's demand forecast.
Batch, streams, files and APIs: the 4 ways data moves, and how an interviewer scores each answer.
- Category
- Pipeline Architecture
- Difficulty
- beginner
- Duration
- 20 minutes
- Challenges
- 4 hands-on challenges
Topics covered: Batch Processing, Stream Processing, File Ingestion, API Ingestion, Batch vs Streaming
Lesson Sections
- Batch Processing
The question arrives as 'walk me through how you would produce yesterday's sales numbers every morning,' or in its bluntest form, 'what is batch processing?' Either way the interviewer is checking the same thing: whether you can describe a job that takes a bounded set of data and runs until it has written a result someone reads later. The scoring sheet for this question is short, and most candidates lose points by skipping an item on it rather than by saying anything wrong. What batch means A ba
- Stream Processing
This one shows up as 'how would you flag a stolen card before the second swipe goes through?' or 'what changes when the data never stops arriving?' The interviewer wants 2 things: an accurate picture of what a stream is, and a justification for paying for it, because a stream costs more to build and to run than a nightly job, and choosing one without a reason is the most common way to lose this question. What a stream is A stream is an unbounded input. Events keep arriving, there is no last row,
- File Ingestion
The question arrives as 'a payment processor drops a CSV of settlements into a bucket every night. How would you load it?' Candidates who have only loaded files on a laptop describe reading the file and inserting the rows. Candidates who have loaded files in production describe everything that goes wrong between the processor's upload and your table, and that gap is exactly what this question measures. Is the file complete? The ledger Every production file loader keeps a table of what it has loa
- API Ingestion
'Our CRM vendor exposes a REST API. Pull every customer record into the warehouse once a day.' The follow-ups are predictable, and they arrive in the same order in almost every interview: how do you get all of them, what happens when the vendor slows you down, what happens when a call fails, and how do you avoid pulling 2 million records every day when 3,000 changed. An answer that covers those 4 before they're asked is the one that scores. Following the pages No API returns 2 million records in
- Batch vs Streaming
This is the decision question, and it comes in 1 disguise after another: 'should the signups dashboard be real time?', 'would you stream the warehouse scans?', 'the product manager wants live numbers, what do you build?' The interviewer is scoring 1 move above all others: whether you ask about freshness before you choose. Answering 'streaming' in the first 3 seconds, because it sounds current, loses the question even when streaming turns out to be the right call. The question to ask back 'How st