33
44"""Model misconfiguration fault in the Flower application."""
55
6+ import os
67import time
7- from typing import Any
8+ from typing import Any , Callable
89
910from aiopslab .orchestrator .tasks import *
1011from aiopslab .service .dock import Docker
1314from aiopslab .session import SessionItem
1415from aiopslab .generators .fault .inject_virtual import VirtualizationFaultInjector
1516
17+ WORKLOAD_START_TIMEOUT_SECONDS = int (
18+ os .getenv ("AIOPSLAB_FLOWER_WORKLOAD_START_TIMEOUT_SECONDS" , "300" )
19+ )
20+ FAULT_PROPAGATION_TIMEOUT_SECONDS = int (
21+ os .getenv ("AIOPSLAB_FLOWER_FAULT_PROPAGATION_TIMEOUT_SECONDS" , "300" )
22+ )
23+
1624
1725class FlowerModelMisconfigBaseTask :
1826 def __init__ (self , faulty_service : str = "user-service" ):
@@ -25,30 +33,48 @@ def __init__(self, faulty_service: str = "user-service"):
2533 def start_workload (self ):
2634 print ("== Start Workload ==" )
2735 command = "flwr run train local-deployment"
28- self .docker .exec_command (command , cwd = self .train_dir )
36+ self .docker .exec_command (
37+ command ,
38+ cwd = self .train_dir ,
39+ timeout = WORKLOAD_START_TIMEOUT_SECONDS ,
40+ )
2941
3042 path = "/app/.flwr/apps"
3143 check = f""" docker exec -it { self .faulty_service } sh -c "test -d { path } && echo 'exists'" """
3244
3345 print ("Waiting for workload to start..." )
34- while True :
35- exists = self . docker . exec_command ( check )
36- if exists . strip () == "exists" :
37- break
38- time . sleep ( 1 )
46+ self . _wait_until (
47+ "Flower workload start" ,
48+ lambda : self . docker . exec_command ( check ). strip () == "exists" ,
49+ WORKLOAD_START_TIMEOUT_SECONDS ,
50+ )
3951 print ("Workload started successfully." )
4052
4153 # Inject fault after workload starts, since the required files are created during the workload
4254 print ("Injecting fault..." )
4355 self .inject_fault (inject = True )
4456
4557 print ("Waiting for faults to propagate..." )
46- while True :
47- logs = self . docker . get_logs ( self . faulty_service )
48- if "error" in logs . lower ():
49- break
50- time . sleep ( 1 )
58+ self . _wait_until (
59+ "Flower fault propagation" ,
60+ lambda : "error" in self . docker . get_logs ( self . faulty_service ). lower (),
61+ FAULT_PROPAGATION_TIMEOUT_SECONDS ,
62+ )
5163 print ("Faults propagated." )
64+
65+ def _wait_until (
66+ self ,
67+ description : str ,
68+ predicate : Callable [[], bool ],
69+ timeout_seconds : int ,
70+ interval_seconds : float = 1 ,
71+ ):
72+ deadline = time .monotonic () + timeout_seconds
73+ while time .monotonic () < deadline :
74+ if predicate ():
75+ return
76+ time .sleep (interval_seconds )
77+ raise TimeoutError (f"{ description } did not complete within { timeout_seconds } seconds." )
5278
5379 def inject_fault (self , inject : bool = False ):
5480 print ("== Fault Injection ==" )
0 commit comments