A scheduler can repeat a task in two ways: start each run at a fixed interval measured from the previous run's *start*, or begin counting the interval only after the previous run *finishes*. Compare the two semantics and explain how you would choose between them.
answer
- fixed rate preserves FREQUENCY; fixed delay preserves the GAP
- rate: due = start0 + n·period (drift-free timeline)
- delay: actual period = execution + delay (drifts forever)
- E > P under fixed rate ⇒ back-to-back, no idle time
- polling ⇒ fixed delay; sampling/heartbeat ⇒ fixed rate
basics
~20 sFixed-rate anchors each run to a fixed timeline from the first start, so run count over time is preserved and execution time eats into the gap. Fixed-delay measures the gap from the end of the previous run, so the actual period is interval plus execution time and drift accumulates.
solid answer
~60 s**Fixed rate**: run *n* is due at `start0 + n × period`, regardless of how long runs take. The schedule is an absolute timeline, so long-run frequency is exactly one per period and errors do not accumulate. If a run takes longer than the period, the next is already overdue and starts immediately when possible — and after a stall, several runs may be due at once, producing a catch-up burst. **Fixed delay**: the next run is due `delay` after the previous run *ends*. The effective period is `execution time + delay`, so it varies with load and the schedule drifts steadily away from any wall-clock alignment. In exchange, there is always a guaranteed idle gap between runs and never a burst. **Choose fixed rate** when the *cadence itself* is the requirement — sampling at a known frequency, emitting a heartbeat, aligning to time buckets. **Choose fixed delay** when you need a guaranteed rest between runs — polling an external system, work whose duration varies widely, or anything where back-to-back execution would be harmful.
code
text · 13 linesFIXED RATE (due = start0 + n*10)
0s [===run 3s===] gap 7s
10s [===run 3s===] gap 7s
20s [===run 3s===] -> 360 runs/hour, gaps shrink as E grows
FIXED DELAY (next due = previous end + 10)
0s [===run 3s===] wait 10s
13s [===run 3s===] wait 10s
26s [===run 3s===] -> ~277 runs/hour, gap always exactly 10s
EXECUTION SLOWER THAN PERIOD (E=15s, P=10s)
fixed rate : run, run, run ... back-to-back, zero idle, period degrades to 15s
fixed delay: [15s run] wait 10s [15s run] ... period 25s, target still gets quietgo deeper
Give the definitions clearly: fixed rate measures the interval from the previous start, fixed delay from the previous finish, so with fixed delay the real period includes the run's duration.
Add the arithmetic (period = E + P for fixed delay), the frequency difference over an hour, and the rule of thumb: fixed rate preserves cadence, fixed delay preserves the gap.
Discuss the overrun case where fixed rate degrades into back-to-back execution, catch-up bursts after a stall, and picking fixed delay for anything polling a shared external resource. Mention duration monitoring and per-run timeouts.
Frame it as a contract with downstream systems: whether the consumer needs cadence guarantees or protection from bursts, how missed-run policy is specified, and when a fixed interval must be replaced by a calendar-aware or distributed scheduler.
## The two schedules, precisely Let the first run start at time `S0`, each run take `E` to execute, and the configured interval be `P`. **Fixed rate.** Run *n* is due at `S0 + n·P`. The due times form a fixed timeline computed once, from the first start, and execution duration does not shift it. The *gap* between the end of one run and the start of the next is `P − E`, which shrinks as runs get slower and reaches zero when `E = P`. **Fixed delay.** Run *n+1* is due `P` after run *n* **ends**. The period is therefore `E + P`, and the timeline is recomputed from reality after every run. The gap between runs is always exactly `P`. With `P` = 10 s and `E` = 3 s: fixed rate starts at 0, 10, 20, 30 (frequency 0.1/s, gaps of 7 s). Fixed delay starts at 0, 13, 26, 39 (frequency ≈ 0.077/s, gaps of 10 s). After an hour, fixed rate has run 360 times and fixed delay about 277 — a 23% difference that surprises people who thought the interval meant the same thing in both. ## Drift Drift is the accumulating divergence between the intended timeline and the actual one. - Fixed rate is **drift-free by construction** for the *nominal* timeline: because each due time is derived from `S0` rather than from the previous run, small lateness in one run does not push later runs. Run 1000 is due at `S0 + 1000·P` no matter what happened in between. - Fixed delay **drifts without bound**. Every run's execution time and every scheduling delay is added permanently to the timeline. A job intended to run "every minute" and taking 4 seconds actually runs every 64 seconds and will have lost about 90 runs per day relative to a fixed-rate schedule. This is the single most useful sentence to remember: *fixed rate preserves frequency, fixed delay preserves the gap.* ## Behavior when a run is slower than the interval If `E > P`, fixed rate can never keep up. Standard schedulers do **not** run overlapping instances of a periodic task, so what actually happens is that the next run becomes overdue and starts as soon as the previous one finishes. The effective period degrades to `E` — the schedule silently becomes back-to-back execution with no idle time at all. That is often the worst possible behavior for a task that hammers a database: the moment it gets slow, it also runs constantly. Fixed delay handles the same situation gracefully: the period simply stretches to `E + P`, and the target still gets `P` of quiet between runs. This self-limiting property is why fixed delay is the safer default for anything that touches a shared external resource. ## Catch-up bursts With fixed rate, if the process is stalled — a long garbage-collection pause, CPU throttling, a blocked worker, or a suspended virtual machine — several due times may pass while nothing runs. When the scheduler recovers, all those runs are overdue at once. Depending on the implementation, you get either a rapid burst of back-to-back executions to "catch up," or a single immediate run. A burst is dangerous: the system just recovered from being overloaded, and the scheduler immediately adds a spike of work. Fixed delay cannot produce this at all: it only ever knows about one pending run. ## Choosing Use **fixed rate** when the cadence is the point: - Sampling metrics at a known frequency, where a missing sample is a hole in a time series. - Heartbeats and liveness signals whose consumer expects a fixed interval. - Work aligned to time buckets (per-minute aggregation), where slipping past a bucket boundary corrupts the result. Use **fixed delay** when the gap is the point: - Polling an external API, database, or queue, where the interval is really "be polite between attempts." - Work with highly variable duration, so the period would otherwise collapse to zero. - Cleanup, compaction, and retry loops, where you want guaranteed quiet time and never a burst. ## Practical guardrails Whichever you pick: 1. **Measure execution duration** and alert if it approaches the period. `E ≈ P` under fixed rate is the point where your schedule silently becomes continuous execution. 2. **Bound the task** with its own timeout so a single hung run cannot suspend the schedule indefinitely. 3. **Cap catch-up.** If you use fixed rate, decide explicitly whether missed runs should be skipped (usually) or replayed, rather than letting the default produce a burst. 4. **Do not encode alignment in a period.** "Every 24 hours" is not "every day at midnight" — over time it slides, and it ignores time-zone and daylight-saving changes. Absolute calendar schedules need a calendar-aware scheduler, not a fixed interval.
- A fixed-rate job runs every 10 seconds and normally takes 2 seconds. Its execution time grows to 12 seconds. What happens?The next run is overdue before the current one finishes, and since schedulers do not run overlapping instances of a periodic task, each run starts immediately after the previous ends. The effective period becomes the execution time — 12 seconds — with zero idle gap, so the job now runs continuously against whatever resource it uses. That is the classic failure mode: the task becomes most aggressive exactly when the system is slowest.
- After a long process pause, a fixed-rate task fires several times in quick succession. Why, and what would you do about it?Several due times elapsed while nothing ran, so on recovery they are all overdue and the scheduler executes them back to back to catch up. That spike arrives right when the system is fragile. The fix is an explicit missed-run policy: skip missed occurrences and re-anchor to the next due time, or coalesce them into a single run, rather than replaying every one.
- Is "every 24 hours" with a fixed-rate schedule the same as "every day at midnight"?No. A fixed interval measures elapsed time, so the run time slides with each restart, with scheduling jitter, and with any process downtime — after weeks it can be hours off. It also ignores time zones and daylight-saving transitions, where a calendar day is not always 24 hours. Calendar-anchored requirements need a calendar-aware scheduler expressing an absolute time, not an interval.
Fixed rate is a bus timetable: the 9:00 bus is due at 9:00 whether or not the 8:00 one ran late, and a delayed bus means two arrive together. Fixed delay is a queue at a ticket window: the next person is called a fixed time after the previous one leaves, so the whole line simply slides later.
saying these in an interview costs you the question
- Believing both modes produce the same number of runs per hour — they differ by the execution time.
- Assuming fixed rate runs overlapping instances when a run overruns; standard schedulers serialize them instead.
- Claiming fixed delay is drift-free; it drifts by the execution time on every single run.
- Using fixed rate for polling an external system, so the poll becomes continuous exactly when that system slows down.
- Treating a 24-hour fixed interval as a daily calendar schedule, ignoring drift, time zones, and daylight saving.