In SimulationBank, tellers are the finite resources that customers compete for. Effective resource management ensures customers are served efficiently while maintaining realistic constraints.
Defined in backend/src/teller/domain/teller.py:11:
@dataclassclass Teller: """ Entidad: ventanilla (cajero) del banco Representa un recurso del sistema que atiende clientes uno a la vez. """ id: str # Identificador alfanumérico de la ventanilla (ej. 'T-1') status: TellerStatus = TellerStatus.IDLE # Estado operativo actual (libre, ocupado o averiado) current_customer: Optional[Customer] = None # Referencia al cliente que está siendo atendido en este momento sessions_served: int = 0 # Contador que acumula cuántos clientes han sido atendidos exitosamente
# backend/src/teller/domain/teller_status.pyclass TellerStatus(Enum): IDLE = "IDLE" # Ready to serve BUSY = "BUSY" # Currently serving BROKEN = "BROKEN" # Out of service (future)
def start_service(self, customer: Customer, current_time: float) -> None: """ Inicia el proceso de atención para un cliente específico. Cambia el estado de la ventanilla a ocupado (BUSY). Registra el cliente actual y actualiza el estado del cliente a 'BEING_SERVED', guardando el momento exacto en el que inició su servicio. """ self.status = TellerStatus.BUSY self.current_customer = customer customer.status = "BEING_SERVED" customer.service_start_time = current_time
1
Change teller status
IDLE → BUSY
2
Assign customer
Store reference to Customer entity
3
Update customer status
Customer: WAITING → BEING_SERVED
4
Record start time
Timestamp when service began (for wait time calculation)
def end_service(self) -> Optional[Customer]: """ Finaliza el servicio del cliente que está siendo atendido actualmente. Cambia el estado del cliente a completado ('COMPLETED'). Libera la ventanilla cambiándola a estado 'IDLE'. Incrementa el número de sesiones servidas y devuelve el cliente que finalizó. """ if not self.current_customer: return None served = self.current_customer served.status = "COMPLETED" self.current_customer = None self.status = TellerStatus.IDLE self.sessions_served += 1 return served
def _assign_free_teller(self) -> None: """ Busca secuencialmente si existe una ventanilla inactiva (IDLE). En caso de encontrar una y haber gente esperando, extrae al primer cliente de la fila y programa el evento SERVICE_START para esa ventanilla en el reloj actual. """ if not self.waiting_queue: return for t_id, teller in self.tellers.items(): if teller.status == "IDLE" or getattr(teller.status, "value", None) == "IDLE": next_customer = self.waiting_queue.pop(0) # Get highest-priority customer # Schedule immediate SERVICE_START self.schedule_event(SimulationEvent(self.clock, EventType.SERVICE_START, customer=next_customer, teller_id=t_id)) return # Assign only one customer per call
max_queue_capacity: int = 100 # Maximum waiting queue size
Currently, max_queue_capacity is defined but not enforced in the code. Customers are always added to the queue regardless of capacity.Future enhancement: Reject customers (balking) when queue is full.
Symptom: Queue grows continuouslyDiagnosis: ρ ≥ 1 (arrival rate exceeds service capacity)Solution: Increase num_tellers or decrease arrival_rate
Tellers frequently idle
Symptom: Low sessions_served, high idle timeDiagnosis: ρ ≪ 1 (excess capacity)Solution: Reduce num_tellers to match demand
Uneven teller workload
Symptom: Some tellers have much higher sessions_servedCause: Random variation in service times (normal with exponential distribution)Solution: Use more deterministic service times or larger simulation runs
Customers wait despite idle tellers
Bug indicator:_assign_free_teller() not called correctlyCheck: Ensure it’s called after ARRIVAL and SERVICE_END events