Infrastructure primitives
Distributed cron - exactly one runner at nine o'clock
Why a scheduled job needs a lease so it runs once, not once per server, and what a missed tick should do.
What this board gets wrong on purpose
The tension
The lease and the unique run row make SCHEDULING exactly-once; nothing makes EXECUTION exactly-once. A worker that charges the customer and then dies before marking the run finished is indistinguishable, to the reaper, from one that died before charging - so the run is retried and the customer is charged twice unless the job itself is idempotent. The fencing token only protects stores that check it: the billing database rejects a stale token, the email provider does not, so a stale worker still sends the invoice email. The board also aligns everybody on the hour: 18,000 hourly jobs plus every five-minute and every-minute job fire in the same second at :00 - about 28,000 runs every hour and 33,000 at midnight UTC, against an average of 52 a second - so the 09:00 job a customer cares about starts at 09:06 behind the queue. And Europe/Berlin has no 02:30 on the last Sunday in March and two of them in October; the misfire policy field does not say which of those a job wants.
Practise this as an interview
Take Distributed cron - exactly one runner at nine o'clock as a timed system design interview on a blank board - on your own, with the requirements to check yourself against, or with a candidate you invite.
Start here
Why this design
Every company starts with a crontab on one box and eventually loses a month-end report because that box was being patched at midnight. The next step - the same crontab on three boxes - sends every customer three invoices. A distributed scheduler is the answer, and it is a good interview question because the obvious fix (leader election) is necessary, insufficient, and comes with a failure mode that only a fencing token handles. Then the real question arrives: the job ran once, but did it happen once?
What you will learn
- How a lease with a fencing token elects one ticking scheduler, and why the lease alone still allows two leaders for a few seconds.
- Why a unique constraint on (job_id, scheduled_for) is the actual exactly-once mechanism for scheduling.
- Misfire policies - skip, once, catch up - and why each job needs its own.
- Why execution is at-least-once no matter what the scheduler does, and what idempotent jobs look like.
- Why the top of the hour is a thundering herd 630 times the average rate, and how jitter flattens it.
How to read this board
- Press Play: the walkthrough follows the 09:00 invoice job from its definition through the lease, the claim and the queue, then breaks it twice.
- DEFINITIONS (left) is what should run and the alarm for what did not; THE TICK (middle) is one leader and one row per run; EXECUTION (right) is where exactly-once ends.
- 1 · Requirements, 2 · Capacity and 3 · Storage - including the 33,000-run second at midnight.
- 4 · Availability - a scheduler outage is silent, which is why the dead-man's switch is on the board.
- 5 · How it works in prose, then 6 · Deployment - including how to deploy the scheduler without missing a tick.
- Finally the DATA MODEL, then argue with the weakness: scheduling is exactly-once and execution is not.
1 · Requirements
Ask these before drawing anything
- What precision is needed - to the second, or within a minute? Second-level precision at scale means a leader scanning every second; minute-level allows a much lazier design.
- What should happen to a run missed during an outage? A report wants one late run; a cache warmer wants none; a metering job wants every interval it missed.
- May two runs of the same job overlap if one runs long? Forbid, allow, or replace the old one - another per-job field.
- Which timezone is "nine o'clock"? A customer's local nine moves twice a year relative to UTC, and on two days a year some local times do not exist or happen twice.
- Are the jobs ours or the customers'? A multi-tenant scheduler needs per-tenant limits, or one tenant scheduling 10,000 jobs at midnight starves everyone.
- Is the job itself idempotent? If not, no scheduler design delivers exactly-once, and the requirement belongs to the job owner.
Functional
- Register jobs with a cron expression, a timezone, a misfire policy, an overlap policy and a maximum runtime.
- Fire each scheduled occurrence once, on time, from exactly one scheduler.
- Dispatch each run to a worker, track it by heartbeat, and retry runs whose worker disappeared.
- Hand every run a fencing token that downstream writes can check.
- Alert when an expected successful run has not happened by its deadline.
Non-functional
- Fire time: within 2 s of the scheduled second at p99, outside the top-of-hour herd.
- Leader failover: under 15 s, with missed ticks handled by policy rather than lost.
- No duplicate run rows, ever - enforced by the database, not by code.
- Scheduler down for an hour must not silently drop an hour of runs.
Out of scope
- Workflow DAGs (job B after job A succeeds) - that is an orchestrator built on top of this.
- Sub-second timers and per-user delayed messages - a delay queue, not cron.
- The job code itself, beyond the contract that it must be idempotent.
The rest of this board
Available on Tier Slate
This page publishes the question. The answer — 5 more written pages, an 8-step narrated walkthrough and a 5-table schema — is the board itself, and it opens in Tierslate.
- 5written pages
- 8walkthrough steps
- 5tables30 columns
5 pages behind this one
- Capacity estimation
- Storage estimation
- Availability
- How it works
- Deployment plan
More boards
The building blocks an interview asks you to build from scratch.
- URL shortener - one write, a million reads
- Distributed cache - the ring, and what a node leaving costs
- Key-value store - quorums, and where the consistency knob sits
- Rate limiter - token bucket, and where the counter lives
- Unique ID generator - 64 bits, and two facts nobody can check
- Web crawler - a frontier, and the trap of crawling forever
- Pastebin - a blob store with a short name
- Load balancer - spreading traffic, and noticing who is dead
- API gateway - one front door for many services
- Login and sessions - who you are, on every request
- Feature flags - a config change that ships like code
- Secrets manager - the one store everything trusts
- DNS - the cache that runs the internet
- Background job queue - at least once, and the retry that doubles it
- Code execution sandbox - running a stranger's program
- Distributed log - Kafka from the partition up
- Consensus - a leader, a log, and a majority
- Object storage - eleven nines from cheap disks