Queue Simulation with M/M/c/K Algorithm

This post presents the M/M/c/K extension of the M/M/c queueing model, implemented in QueueForge. QueueForge now supports both models — M/M/c (infinite capacity) and M/M/c/K (finite capacity) — selectable via a dropdown in the parameters panel. If you are new to queueing theory and the M/M/c model, please read the introductory post Queue Simulation with M/M/c Algorithm first — it covers Kendall's notation, Poisson arrivals, the Erlang C formula, and Little's Law. This post focuses exclusively on the finite-capacity variant and how it changes the mathematical analysis.

The application is freely accessible at: https://computationalmindset.com/apps/QueueForge?model=mmck

From M/M/c to M/M/c/K: Finite System Capacity

The M/M/c model assumes an unlimited waiting room: any number of customers can queue up while all servers are busy. In practice, many real systems have a physical or logical upper bound on the total number of customers allowed (queue + servers combined). When the system is full, new arrivals are rejected (lost or blocked).

In Kendall's notation A/B/c/K/N/D, the fourth field K specifies the maximum number of customers in the system (waiting plus being served). An M/M/c/K system therefore has:

  • M (first): Poisson arrivals with rate $\lambda$
  • M (second): exponential service times with rate $\mu$ per server
  • c: number of parallel identical servers
  • K: maximum system capacity — must satisfy $K \geq c + 1$

Two immediate consequences distinguish M/M/c/K from M/M/c:

  • Always stable: because the queue is bounded, the system is always in steady state regardless of the ratio ρ. Even with λ > cμ the system never overflows indefinitely.
  • Rejection probability: a customer arriving when the system is at capacity K is turned away. This probability must be computed and factored into all performance metrics via an effective arrival rate.

The M/M/c/K Mathematical Model

State probabilities

The steady-state probability $P_n$ of having $n$ customers in the system is: $$P_n = \begin{cases} P_0 \cdot \dfrac{a^n}{n!} & 0 \le n \le c \\[6pt] P_0 \cdot \dfrac{a^c}{c!} \cdot \rho^{n-c} & c < n \le K \end{cases}$$ where $a = \lambda / \mu$ is the offered load and $\rho = \lambda / (c \cdot \mu)$ is the server utilization. The normalization constant $P_0$ (probability the system is empty) is obtained by imposing $\sum_{n=0}^{K} P_n = 1$: $$P_0 = \frac{1}{\displaystyle\sum_{k=0}^{c-1} \frac{a^k}{k!} \;+\; \frac{a^c}{c!} \cdot \frac{1 - \rho^{K-c+1}}{1 - \rho}} \qquad (\rho \ne 1)$$ When $\rho = 1$ the geometric sum degenerates and the denominator becomes: $$\sum_{k=0}^{c-1} \frac{a^k}{k!} + \frac{a^c}{c!} \cdot (K - c + 1)$$

Rejection probability

The probability that the system is full — and an arriving customer is rejected — is $P_K$: $$P_K = \begin{cases} P_0 \cdot \dfrac{a^K}{K!} & K \le c \\[6pt] P_0 \cdot \dfrac{a^c}{c!} \cdot \rho^{K-c} & K > c \end{cases}$$ $P_K$ is sometimes called the loss probability or blocking probability.

Effective arrival rate

Because a fraction $P_K$ of all arrivals is lost, the rate of customers that actually enter the system is: $$\lambda_{\text{eff}} = \lambda \cdot (1 - P_K)$$ All performance metrics must be computed with $\lambda_{\text{eff}}$ rather than the nominal $\lambda$, otherwise Little's Law would be violated.

Average queue length

The average number of customers waiting (not being served) is: $$L_q = \frac{a^c \cdot \rho \cdot P_0}{c!} \cdot \frac{1 - \rho^{K-c+1} - (K-c+1)\,\rho^{K-c}(1-\rho)}{(1-\rho)^2} \qquad (\rho \ne 1)$$ When $\rho = 1$: $$L_q = \frac{a^c \cdot P_0}{c!} \cdot \frac{(K-c)(K-c+1)}{2}$$

Remaining performance metrics

All other metrics are derived from $L_q$ and $\lambda_{\text{eff}}$ using Little's Law:

Average number of customers in the system $L$: $$L = L_q + \frac{\lambda_{\text{eff}}}{\mu}$$

Average waiting time in queue $W_q$: $$W_q = \frac{L_q}{\lambda_{\text{eff}}}$$

Average time in the system $W$: $$W = \frac{L}{\lambda_{\text{eff}}}$$

Comparison with M/M/c

When $K \to \infty$ the M/M/c/K formulas converge to the M/M/c results: $P_K \to 0$, $\lambda_{\text{eff}} \to \lambda$, and the $L_q$ formula reduces to the Erlang C expression $C(c,a) \cdot \rho / (1-\rho)$. In a finite-capacity system the queue is always shorter (some customers are rejected before queuing), so $L_q^{(K)} \le L_q^{(\infty)}$ for any $K$ and any $\rho$.

Numerical example: M/M/1/5 queue

Consider an overloaded single-server system with $c = 1$, $K = 5$, $\lambda = 10$ arrivals/min, and $\mu = 8$ customers/min — a configuration that would be unstable as a plain M/M/1 ($\rho = 1.25 > 1$), but is always stable under M/M/1/5:

  • Server utilization: $\rho = 10 / (1 \times 8) = 1.25$ (overloaded, yet stable thanks to $K$)
  • Rejection probability: $P_5 \approx 0.271$ (about 27.1% of arrivals are turned away)
  • Effective arrival rate: $\lambda_{\text{eff}} = 10 \times (1 - 0.271) \approx 7.29$ customers/min
  • Average queue length: $L_q \approx 2.22$ customers
  • Average time in system: $W = L / \lambda_{\text{eff}} \approx 0.43$ min = 25.8 seconds
Increasing $K$ reduces the rejection probability, lengthens the queue, and the system approaches M/M/1 instability as $K \to \infty$.

Simulation of M/M/c/K

The QueueForge simulation engine handles the finite-capacity case by extending the standard M/M/c time-stepped simulation with a single additional rule: when a new arrival is generated and the current number of customers in the system equals $K$, the customer is rejected and the rejection counter is incremented. All other mechanics (Bernoulli arrival trials with $p = \lambda \cdot \Delta t$, service completion trials with $p = \mu \cdot \Delta t$ per busy server, FIFO queue management) remain identical to the M/M/c simulation described in Queue Simulation with M/M/c Algorithm.

This allows the simulation to directly estimate the empirical rejection rate, which converges to the theoretical $P_K$ as simulation time increases. The rejection rate exposed by the simulation engine is: $$\hat{P}_K = \frac{\text{total rejected}}{\text{total arrivals}}$$

User Interface and Interaction

QueueForge provides a Queue Model dropdown at the top of the parameters panel to switch between M/M/c and M/M/c/K at any time. The M/M/c/K model can also be opened directly via the URL parameter ?model=mmck (e.g. .../QueueForge?model=mmck); switching the dropdown updates the URL automatically so the link stays shareable.

When M/M/c/K is selected, an additional Max Capacity (K) slider appears alongside the standard parameters ($\lambda$, $\mu$, $c$, simulation speed). The metrics panel additionally shows:

  • Rejection probability: theoretical PK and empirical rejection rate side by side
  • Effective arrival rate: the actual throughput entering the system

Technical Implementation

The M/M/c/K model is implemented in the MMCKQueueingModel class (src/models/MMCKQueueingModel.ts), a companion to the MMCQueueingModel class for the unconstrained case. The simulation engine in QueueSimulation.ts accepts an optional maxCapacity parameter: when provided it activates M/M/c/K mode transparently, without changing the simulation loop structure.

The overall architecture remains the same four-layer design:

  1. Models layer (models/): MMCKQueueingModel implements P0, PK (Erlang B blocking probability), Lq and all derived metrics with the closed-form formulas above
  2. Simulation layer (simulation/): QueueSimulation with maxCapacity for rejection tracking
  3. Visualization layer (visualization/): Canvas chart unchanged; the rejection rate is shown in the metrics panel
  4. UI layer (components/, App.tsx): React components with an additional K slider

The test suite in src/models/__tests__/MMCKQueueingModel.test.ts verifies known M/M/1/K and M/M/2/K values, validates the Erlang B blocking probability against published tables, checks that $P_K \to 0$ as $K \to \infty$, and confirms that $\lambda_{\text{eff}} \le \lambda$ always holds.

Try QueueForge

Experience QueueForge with the M/M/c/K model directly in your browser:

Launch QueueForge (M/M/c/K)

The application requires no installation and works on any modern web browser. For the best experience, use a recent version of Chrome, Firefox, Safari, or Edge.

Development and Contribution

The M/M/c/K extension of QueueForge was developed with Claude Code following the BMAD (Breakthrough Method of Agile AI-driven Development) approach, as part of a continued exploration in AI-assisted software development for educational tools.

The project follows standard modern TypeScript and JavaScript development practices:

Clone the repository:

git clone https://github.com/ettoremessina/QueueForge.git
cd QueueForge

Install dependencies:

npm install

Run development server:

npm run dev
This starts a local development server with hot module replacement for rapid iteration.

Build for production:

npm run build
The optimized output is generated in the dist/ folder and can be deployed to any static hosting service.

Run tests:

npm test

Source Code and License

The complete source code is available on GitHub at this address: QueueForge.

These materials are distributed under MIT license; feel free to use, share, fork and adapt these materials as you see fit.
Also please feel free to submit pull-requests and bug-reports to this GitHub repository or contact me on my social media channels available on the top right corner of this page.