Why this matters: a scheduler sounds like a clock and a to-do list, which is exactly why it makes a good interview: every candidate can start, and the design quality separates fast. The requirements conversation decides whether you'll spend the round on the real problems — time, recurrence semantics, dependencies — or discover them one ambush at a time.
The prompt, as given
Design an in-process task scheduler.
Callers hand it work to run later: at a specific time, after a delay, on a repeating interval, or only after other tasks have finished. Execution itself is not your problem — a worker pool is provided and you submit runnable tasks to it. Deciding when each task becomes runnable, and in what order, is entirely yours.
Read the scope gift in the second sentence: execution is somebody else's problem. The pool is given; it outlives you; you submit runnables to it. Candidates who start designing worker threads have missed the boundary the prompt drew for them — and interviewers notice boundary-reading the way they notice requirements-gathering, because it is the same skill.
The question that separates candidates
"How do you want me to handle time?" — or better, stated as a decision: "I'm going to inject a clock rather than read the system time, so every scheduling claim I make is testable with a fake clock." Time is this problem's hidden dependency. A scheduler that calls the system clock directly cannot be tested without sleeping through real minutes, and every claim about "fires at 10:00" becomes a claim you can't demonstrate. Injecting the time source is the same move the rate-limiter chapter made, for the same reason — and interviewers listen for it here specifically, because so few candidates think of time as a dependency at all.
The remaining questions, and why each matters
"What does 'every five minutes' mean when a run takes six?" The recurring-overlap question — ask it before the interviewer asks you. There are three coherent answers: skip the overlapped fire, queue exactly one pending fire, or run concurrently. Skip and queue-one are the defensible defaults; concurrent execution of a task with itself needs a positive reason. What's graded is not which you pick but that you saw the collision and chose on purpose.
"What exactly does run-after-tasks promise?" Dependencies need precise semantics: here, all parents must succeed. Which forces the next question — what happens to children when a parent fails? Answer: they're marked skipped, not silently dropped; an unobservable no-op is operationally indistinguishable from a bug. Diamond shapes (two paths to the same descendant) are allowed; cycles must be rejected at submission, because a cycle discovered at runtime has no good answer.
"What happens to fires we slept through?" If the process pauses and wakes past several fire times: skip the missed occurrences and run the next future one. The alternative — catch-up storms replaying every missed fire — is occasionally what's wanted, but not by default and not in v1.
"Scale and operations?" Around ten thousand scheduled tasks, one process; cancellation by task id is in scope. That number matters: it licenses one ordered structure and one dispatcher, not a sharded time service.
The requirement set this chapter builds against
Modes run-at(time) · run-after(delay) · run-every(interval)
· run-after-tasks(parents)
Executor GIVEN: a worker pool with submit(runnable); outlives us
Time injected clock — all claims testable with a fake clock
Overlap recurring task still running at next fire: SKIP that fire
Dependencies all parents SUCCEED; parent failure -> descendants skipped;
diamonds allowed; cycles rejected at submission
Missed fires skip; run the next future occurrence
Scale ~10k tasks, single process; cancel by task id
As with every chapter: a live interviewer's answers may differ — theirs might want queue-one overlap or catch-up on missed fires. The skill is surfacing each decision before it surfaces you.
Key takeaway
The scheduler's requirements conversation runs on four decisions candidates usually discover too late: time as an injected dependency (the testability question interviewers listen for), what a recurring interval means when runs overlap its fires, what dependencies promise on parent failure, and what happens to fires you slept through. Pin all four, say the executor boundary back, and the design act starts on solid ground.