Offered load and the erlang
The starting point for any staffing calculation is the offered load, measured in erlangs: the arrival rate multiplied by the average handling time. A hundred and twenty calls an hour, each lasting five minutes, is 120 × 300 s / 3600 s = 10 erlangs — meaning that on average ten calls are in progress at once. An erlang is dimensionless; it is exactly the concurrency Little's Law would give you.
Why Erlang C
The Erlang C model answers the staffing question when callers queue for the next free agent rather than getting a busy signal. Given the offered load and a number of agents, it tells you the probability an arriving call has to wait at all, and from that the average speed of answer and the fraction answered within your target time. The calculator inverts it: it searches upward for the smallest number of agents that meets a service-level target such as "80% of calls answered within 20 seconds".
Worked example
For 10 erlangs of load and an 80%/20 s target, eleven agents would leave 68% of callers waiting — nowhere near the goal. Fourteen agents brings the service level to 86.7% and drops occupancy to 71%. That jump from the bare minimum is the cost of good service: the last stretch toward zero waiting is expensive, which is exactly the M/M/1 hockey stick playing out with many servers.
The same math sizes thread and connection pools
A thread pool or a database connection pool is an Erlang C system wearing different clothes. Requests are the calls; the time a request holds a thread or connection is the handling time; the pool size is the agent count. If your service takes 200 requests per second and each holds a connection for 25 ms, the base concurrency is 200 × 0.025 = 5 — but a pool of exactly 5 runs at 100% utilization and queues without bound. Sizing to hold the wait probability at 20% gives a pool of 8, with real wait probability around 17%. This is why pools are sized above average concurrency, and by how much.
Assumptions and their limits
Erlang C assumes Poisson (random, independent) arrivals, exponentially distributed handling times, and — importantly — that nobody abandons the queue. Real callers hang up, which makes Erlang C slightly conservative (it over-staffs a little); the Erlang A model adds abandonment if you need it. For pools, bursty non-Poisson traffic makes the tail worse than the model predicts, so treat the result as a floor, not a ceiling.
Related tools: the Little's Law calculator gives the base concurrency these models build on, and the data transfer time calculator handles raw throughput.