Interrupt Handling Design¶
This document describes the double-Ctrl+C interruption handling for remote benchmarks.
Goals¶
- Prevent accidental stops of long-running benchmarks.
- Ensure graceful teardown of remote workloads when a stop is confirmed.
- Provide clear UI feedback.
Architecture¶
The interrupt handling logic is separated into three layers:
- State Machine (
DoubleCtrlCStateMachine) - Pure logic component in
lb_controller/interrupts.py. - Tracks states:
RUNNING->STOP_ARMED->STOPPING->FINISHED. -
Decides action:
WARN_ARM,REQUEST_STOP, orDELEGATE(allow default/force kill). -
Handler (
SigintDoublePressHandler) - Context manager that installs/restores
signal.signal(SIGINT, ...). - Routes signals to the state machine.
-
Executes callbacks based on decision (
on_first_sigint,on_confirmed_sigint). -
Orchestration (
RunService,BenchmarkController) lb_app.services.run_service.RunServiceinstalls the handler and provides UI callbacks.StopTokeninlb_runner.stop_tokensignals intent to stop across threads/processes.BenchmarkControllerandControllerRunnerobserve the token and coordinate teardown.AnsibleRunnerExecutorinterrupts active playbooks when a stop is requested.
Behavior¶
- First Ctrl+C
- State:
RUNNING->STOP_ARMED. - Action: log "Press Ctrl+C again to stop...". Execution continues.
- Second Ctrl+C
- State:
STOP_ARMED->STOPPING. - Action: trigger
StopToken.- Active Ansible playbook is terminated.
- Controller loop breaks.
- Plugin teardown runs (non-cancellable).
- Global teardown runs (non-cancellable).
- Third Ctrl+C (Force)
- State:
STOPPING. - Action: delegate to Python default handler for a forced exit if teardown hangs.
Files¶
lb_controller/interrupts.py: state machine and handler.lb_app/services/run_service.py: wiring to UI and controller.lb_controller/controller.py: phase-aware stop logic.lb_controller/ansible_executor.py: playbook interruption.