Bank Renege Simulation

Customers join a queue with limited patience and may leave before service if the wait is too long.

Level:Intermediate

queuepatienceabandonmentservicebanking

  • Stocks:queue
  • Flows:served, reneged
  • Probes:wait_time, served, reneged

Delays

Learn about delays in systems, how they create oscillations, and their impact on system behavior and decision-making.

Explore Delays
simulation.py

Waiting in line at the bank

Adapted from https://simpy.readthedocs.io/en/latest/examples/bank_renege.html

Customers queue for a lone teller, but everyone has a patience limit. If the line moves too slowly a customer gives up and leaves in frustration.


import random
from tys import probe, progress

Bank with impatient customers.

def simulate(cfg: dict):

    import simpy
    env = simpy.Environment()
    num_customers = cfg["num_customers"]
    arrival_interval = cfg["arrival_interval"]
    time_in_bank = cfg["time_in_bank"]
    min_patience = cfg["min_patience"]
    max_patience = cfg["max_patience"]
    random_seed = cfg.get("seed", 42)

    random.seed(random_seed)

    counter = simpy.Resource(env, capacity=1)

    served = 0
    reneged = 0
    done = env.event()

Handle one customer's visit to the bank.

    def customer(name: str):
        nonlocal served, reneged
        arrive = env.now
        with counter.request() as req:
            patience = random.uniform(min_patience, max_patience)
            results = yield req | env.timeout(patience)
            wait = env.now - arrive
            probe("wait_time", env.now, wait)
            if req in results:
                service_time = random.expovariate(1.0 / time_in_bank)
                yield env.timeout(service_time)
                served += 1
                probe("served", env.now, served)
            else:
                reneged += 1
                probe("reneged", env.now, reneged)
        processed = served + reneged
        progress(100 * processed / num_customers)
        if processed >= num_customers:
            done.succeed({"served": served, "reneged": reneged})

Generate arriving customers.

    def source():
        for i in range(num_customers):
            env.process(customer(f"Customer{i:02d}"))
            t = random.expovariate(1.0 / arrival_interval)
            yield env.timeout(t)

    env.process(source())
    env.run(until=done)
    return done.value


def requirements():
    return {
        "builtin": ["micropip", "pyyaml"],
        "external": ["simpy==4.1.1"],
    }
config.yaml
seed: 42
num_customers: 50
arrival_interval: 5.0
time_in_bank: 12.0
min_patience: 1
max_patience: 3