FCFS Scheduling — Convoy Effect Cripples Payment API
Response time for payment API jumped from <200ms to >15s due to convoy effect in FCFS scheduling.
20+ years shipping performance-critical code where algorithms decide the bill. Everything here is grounded in real deployments.
- Processes execute in arrival order — pure FIFO queue.
- No preemption: once running, a process keeps the CPU until it blocks or exits.
- Convoy effect: a single long job holds the CPU while short jobs wait idle, inflating average waiting time.
- Worst-case average waiting time grows linearly with burst time variance — not robust for interactive loads.
- Production trap: using FCFS for mixed workloads (CPU + I/O) causes I/O devices to starve, tanking throughput.
FCFS is the simplest scheduling algorithm — processes run in the order they arrive, like a queue at a ticket counter. Whoever arrives first gets served first. Simple and fair in principle, but a long process can make everything behind it wait — the convoy effect.
FCFS is the algorithm you implement when you have a queue and zero information about job durations. It is fair in the sense that arrival order is respected — no process waits longer than all processes that arrived before it. But 'fair' does not mean 'efficient', and the convoy effect makes FCFS genuinely harmful for interactive workloads.
Understanding FCFS matters not for implementing it (it is trivially a FIFO queue) but for understanding what it optimises and what it sacrifices. Every scheduling algorithm trades off fairness, average waiting time, response time, and throughput differently. FCFS optimises arrival-order fairness at the cost of average waiting time. This trade-off analysis is the interview skill being tested.
Why FCFS Scheduling Fails Under Burst Load
First-Come, First-Served (FCFS) is the simplest scheduling algorithm: tasks execute in the exact order they arrive, using a FIFO queue. The core mechanic is non-preemptive — once a task gets the CPU, it runs to completion. This means no context-switch overhead, but it also means a single long task can block every subsequent task, regardless of priority or urgency.
In practice, FCFS exhibits the convoy effect: a long CPU-bound process holds the queue, forcing all I/O-bound tasks to wait. For a payment API, a single large report generation request (say, 2 seconds of CPU) can delay 1000 payment transactions behind it, each adding milliseconds of latency. The average waiting time balloons as the variance in burst times increases — mathematically, the average turnaround time is O(n) in the worst case.
Use FCFS only when all tasks have similar, predictable execution times — for example, a batch processing pipeline where each job is identical. In real-time or interactive systems, FCFS is a liability. Understanding its convoy effect is critical because it's the default behavior of many naive queue implementations (e.g., a simple BlockingQueue in Java) that teams assume are safe.
Algorithm and Metrics
- Completion Time (CT): When the process finishes
- Turnaround Time (TAT): CT
- Arrival Time
- Waiting Time (WT): TAT
- Burst Time
- Response Time: Time from arrival to first execution (= WT for non-preemptive)
FCFS is trivially a FIFO queue. You sort processes by arrival time, then execute each to completion. The metrics tell the real story: average waiting time can skyrocket when a long job arrives early.
The Convoy Effect
In the example above, P2 and P3 each take only 3ms but wait 23ms and 25ms because P1 (24ms) arrived first. This is the convoy effect — short processes form a convoy behind a long one.
- P2: WT=0, P3: WT=2, P1: WT=5
- Average WT = 2.33ms vs 16ms for FCFS
This is why FCFS has poor average waiting time for mixed workloads.
Gantt Chart Representation
A Gantt chart visually shows which process runs at each time interval. For FCFS, the chart is simply the processes in arrival order, each spanning its burst duration. This representation makes the convoy effect obvious: long bars push short bars to the right.
When to Use FCFS in Practice
- All jobs have roughly equal burst times (e.g., batch file processing with similar file sizes).
- Order must be strictly preserved (e.g., transactions that must commit in arrival sequence).
- No prior information about job durations exists and you cannot risk priority inversion.
- Interactive systems where response time matters.
- Mixed workloads with heterogeneous burst times.
- Real-time systems where deadlines must be met.
In most general-purpose operating systems, FCFS is used only as a fallback scheduler for equal-priority processes under SCHED_OTHER. Linux's Completely Fair Scheduler (CFS) is fundamentally different — it's a weighted fair queuing scheduler that preempts to maintain fairness.
- No decision: just a queue. Predictable in behaviour, unpredictable in performance.
- Linux CFS targets a 1ms scheduling granularity — the opposite of FCFS's no-granularity.
- FCFS survives as a special case for cooperative multitasking or dispatcher systems where preemption is impossible.
FCFS vs. SJF vs. Round Robin
Comparing scheduling algorithms around burst time variance:
| Algorithm | Average Waiting Time | Starvation Risk | Preemptive |
|---|---|---|---|
| FCFS | High with variance | None (everyone runs eventually) | No |
| SJF (non-preemptive) | Optimal for given arrival order | Yes, long processes | No |
| Round Robin (preemptive) | Moderate, depends on quantum | Low | Yes |
FCFS minimises the maximum waiting time for processes with the same arrival order — that's its fairness guarantee. But it maximises average waiting time when burst times vary.
SJF exploits knowledge of burst times to minimise average waiting time, but can starve long processes. Round Robin trades off average waiting time for response time — good for interactive workloads.
In production, you rarely pick one in isolation. Hybrid schedulers like CFS combine elements: target latency (like RR) with fairness (like FCFS) and dynamic priority adjustments.
How FCFS Actually Works (No Mysticism)
FCFS is the dumbest scheduling algorithm you'll ever use. That's its superpower. When a process arrives, it gets thrown at the tail of a FIFO queue. The CPU pulls from the head, runs the process to completion (or until it blocks on I/O), then moves to the next. No preemption, no priority, no fancy logic.
The kernel maintains a simple linked list of task_struct entries. Insertion is O(1). Dequeue is O(1). The scheduler has zero decisions to make. That's it. No quantum timers, no context-switch overhead from preemption, no starvation logic because every process eventually hits the front of the line.
Where this breaks down is when you have a long CPU-bound process holding the head of the queue. Every interactive process behind it waits. And waits. The FIFO queue becomes a bottleneck that makes your system feel like it's running on a 486. Windows 95 used a variant of FCFS for some legacy drivers. Users threw their mice at the screen. There's your history lesson.
Example with Different Arrival Times (The Real World)
In production, processes don't all show up at time zero. That's a classroom fantasy. Real workloads have staggered arrivals, I/O bursts, and users who close browsers mid-stream. Let's build a scenario that actually hurts.
Three processes: P1 arrives at 0 with a 7ms CPU burst. P2 arrives at 2ms with a 4ms burst. P3 arrives at 4ms with a 1ms burst. FCFS doesn't care about burst length. P1 runs from 0 to 7. P2 waits until 7, runs to 11. P3 waits until 11, runs to 12. P3's tiny 1ms job sits idle for 7ms while P1 churns.
Calculate turnaround time (completion minus arrival): P1 = 7, P2 = 9, P3 = 8. Average = 8ms. Waiting time (turnaround minus burst): P1 = 0, P2 = 5, P3 = 7. Average = 4ms. P3 waited 7x its execution time. That's the Convoy Effect in its purest form.
Now imagine that P3 is a mouse movement handler. You've just introduced a 7ms input lag. Users don't tolerate that. This is why FCFS is relegated to batch systems and background jobs where latency doesn't matter.
Problem 1: Starvation of Late Arrivals Isn't Fairness
You'd think first-come-first-served is fair by definition. It's not. Late arrivals in FCFS don't just wait — they can wait indefinitely under sustained load. If a CPU-bound process arrives first and runs for 10 seconds, every interactive process that shows up second gets buried behind it. That's not fairness; that's a single-threaded bottleneck masquerading as a policy.
The real problem is that FCFS has no preemption. Once a process gets the CPU, it holds it until it voluntarily yields — usually by completing an I/O wait or terminating. Under burst load, this means short tasks get stuck behind long ones. The average waiting time balloons, and worst-case response time becomes unpredictable.
Why this matters in production: You can't build a real-time system on FCFS. A single misbehaving or oversized job tanks latency for everyone else. If you're running a web server, that's the difference between a 200ms response and a 5-second timeout.
Solution: Preemptive FCFS? No, Use the Right Tool
You can't fix FCFS by making it preemptive — that's not FCFS anymore, that's Round Robin with a quantum. The real solution is admitting FCFS has a narrow sweet spot. If you need bounded response times, use a preemptive scheduler. If you need throughput for batch workloads, FCFS is fine — just don't mix long and short jobs on the same queue.
When you're stuck with FCFS in a legacy system, mitigate by isolating workloads. Use multiple queues: one for short interactive tasks (handled by SJF) and one for long batch jobs (handled by FCFS). This pattern shows up in Linux's Completely Fair Scheduler — it's not preemption that saves you, it's classification.
The production-level fix: never let a single queue mix CPU-bound and I/O-bound processes. Or, if you must, cap the burst time per process and preempt after a threshold. But then you're not running FCFS anymore. Be honest about what you need and choose the algorithm that delivers it.
First-Come, First-Served Scheduling
First-come, first-served (FCFS) scheduling is the simplest CPU scheduling algorithm, where processes are executed in the order they arrive in the ready queue. It follows a non-preemptive, FIFO (First In, First Out) discipline: the first process to request the CPU gets it, and holds it until completion or I/O block. This mimics a real-world queue like a grocery checkout. FCFS is fundamental in operating systems and discrete event simulation because it models natural fairness—no process jumps ahead. However, its simplicity hides severe performance issues under bursty workloads, as average waiting time can balloon when a long CPU burst blocks shorter ones. The algorithm's behavior is purely deterministic: given arrival times and burst durations, the order and completion times are fixed. FCFS is the baseline against which all other scheduling algorithms are measured, despite rarely being used alone in modern systems.
Explanation, Advantages, Disadvantages, and Characteristics
Explanation: FCFS is non-preemptive; once a process gets the CPU, it runs until it terminates or blocks. The scheduler maintains a simple FIFO queue. When a new process arrives, it's appended to the rear. The CPU picks the head of the queue. Advantages: (1) Extremely easy to implement—just a queue. (2) No starvation for CPU-bound processes if they all arrive early; every process eventually runs. (3) Low context-switching overhead. Disadvantages: (1) High average waiting time under bursty loads (convoy effect). (2) Poor response time for interactive processes. (3) Not suitable for time-sharing systems. Characteristics: Non-preemptive, starvation-free in a strict sense (every arrival gets CPU eventually), but average turnaround time can be large. It's deterministic and predictable. The algorithm favors long CPU bursts over short ones, which is the opposite of optimal for minimizing mean wait time. FCFS is the baseline, but in practice, it's used only where order matters (e.g., batch processing) or as a fallback.
Convoy Effect Brings Down an E-Commerce Checkout Service
- Never mix CPU-bound batch jobs and interactive I/O-bound requests on the same FCFS queue.
- Measure queue depth under load — it reveals convoy effect faster than response times alone.
- FCFS belongs in batch systems with homogeneous job sizes, not mixed workloads.
ps -eo pid,comm,etime,pri,nice --sort=start_timefor p in $(pgrep -f batch); do cat /proc/$p/sched | head -20; doneKey takeaways
Common mistakes to avoid
3 patternsAssuming FCFS is 'fair' for all metrics
Using FCFS for I/O-heavy workloads because 'it's simple'
Implementing a thread pool with a single FIFO work queue and claiming it's 'FCFS scheduling'
Practice These on LeetCode
Interview Questions on This Topic
Explain the convoy effect in FCFS scheduling and show it with an example.
Frequently Asked Questions
20+ years shipping performance-critical code where algorithms decide the bill. Everything here is grounded in real deployments.
That's Scheduling. Mark it forged?
8 min read · try the examples if you haven't