66import signal
77import subprocess
88import sys
9+ import time
910import threading
1011from collections import defaultdict
1112from datetime import datetime
2324 compose_down ,
2425)
2526from warnet .utils import (
27+ exponential_backoff ,
2628 gen_config_dir ,
2729 save_running_scenario ,
2830 load_running_scenarios ,
@@ -158,7 +160,7 @@ def run(scenario: str, additional_args: List[str], network: str = "warnet") -> s
158160 [sys .executable , scenario_path ] + additional_args + [f"--network={ network } " ]
159161 )
160162 logger .debug (f"Running { run_cmd } " )
161- process = subprocess .Popen (run_cmd , shell = False )
163+ process = subprocess .Popen (run_cmd , shell = False , preexec_fn = os . setsid )
162164
163165 save_running_scenario (scenario , process , config_dir )
164166
@@ -169,24 +171,45 @@ def run(scenario: str, additional_args: List[str], network: str = "warnet") -> s
169171
170172
171173@jsonrpc .method ("stop_scenario" )
172- def stop_scenario (scenario : str , network : str = "warnet" ) -> str :
174+ def stop_scenario (pid : int , network : str = "warnet" ) -> str :
175+
176+ def is_running (pid ):
177+ try :
178+ os .kill (pid , 0 )
179+ except ProcessLookupError :
180+ return False
181+ return True
182+
183+ @exponential_backoff ()
184+ def kill_process (pid ):
185+ os .kill (pid , signal .SIGKILL )
186+
173187 config_dir = gen_config_dir (network )
174188 running_scenarios = load_running_scenarios (config_dir )
175189
176- if scenario not in running_scenarios :
177- return f"Scenario { scenario } is not running."
190+ scenario = None
191+ for scenario_name , scenario_pid in running_scenarios .items ():
192+ if scenario_pid == pid :
193+ scenario = scenario_name
194+ break
195+ if not scenario :
196+ return f"No active scenario found for PID { pid } ."
178197
179- pid = running_scenarios [scenario ]
180- try :
181- os .kill (pid , 0 )
182- except ProcessLookupError :
183- return f"Scenario { scenario } with PID { pid } is not running."
198+ if not is_running (pid ):
199+ return f"Scenario { scenario } with PID { pid } was found in file but is not running."
184200
201+ # First try with SIGTERM
185202 os .kill (pid , signal .SIGTERM )
203+ time .sleep (5 )
204+ # Then try SIGKILL with exponential backoff
205+ if is_running (pid ):
206+ kill_process (pid )
186207
187- remove_stopped_scenario (scenario , config_dir )
208+ if is_running (pid ):
209+ return f"Could not kill scenario { scenario } with pid { pid } using SIGKILL"
188210
189- return f"Stopped scenario { scenario } ."
211+ remove_stopped_scenario (scenario , config_dir )
212+ return f"Stopped scenario { scenario } with PID { pid } ."
190213
191214
192215@jsonrpc .method ("list_running_scenarios" )
0 commit comments