88
99from costcutter .conf .config import get_config
1010from costcutter .core .session_helper import create_aws_session
11+ from costcutter .reporter import get_reporter
1112
1213# Reporter no longer needed at service-level (resource handlers still record events)
1314from costcutter .services .ec2 import cleanup_ec2
15+ from costcutter .services .s3 import cleanup_s3
1416
1517logger = logging .getLogger (__name__ )
1618
1719SERVICE_HANDLERS = {
1820 # Each value can be a functional entrypoint `run(session, region, dry_run, reporter)`
1921 "ec2" : cleanup_ec2 ,
20- # "s3": cleanup_s3
22+ "s3" : cleanup_s3 ,
2123 # "lambda": cleanup_lambda,
2224}
2325
@@ -55,7 +57,7 @@ def process_region_service(
5557
5658def orchestrate_services (
5759 dry_run : bool = False ,
58- ) -> dict [str , int ]:
60+ ) -> dict [str , Any ]:
5961 config = get_config ()
6062
6163 # Resolve services
@@ -125,6 +127,9 @@ def orchestrate_services(
125127 total_tasks = max (1 , len (tasks ))
126128 max_workers = min (32 , total_tasks )
127129
130+ # Execute tasks concurrently and track successes/failures
131+ succeeded = 0
132+ failed = 0
128133 with ThreadPoolExecutor (max_workers = max_workers ) as executor :
129134 future_map : dict [Any , tuple [str , str ]] = {}
130135 for region , service_key , handler_entry in tasks :
@@ -134,6 +139,23 @@ def orchestrate_services(
134139 for future in as_completed (future_map ):
135140 region , svc_name = future_map [future ]
136141 try :
137- logger .info ("[%s][%s] Task completed" , region , svc_name )
142+ # Propagate exceptions from the task so callers can observe failures
143+ future .result ()
138144 except Exception as e :
145+ failed += 1
139146 logger .exception ("[%s][%s] Task failed: %s" , region , svc_name , e )
147+ else :
148+ succeeded += 1
149+ logger .info ("[%s][%s] Task completed" , region , svc_name )
150+
151+ # After all work is finished, gather recorded events from the global reporter
152+ reporter = get_reporter ()
153+ events = reporter .to_dicts ()
154+
155+ # Return a small summary including counters and serialized events
156+ return {
157+ "processed" : succeeded ,
158+ "skipped" : skipped ,
159+ "failed" : failed ,
160+ "events" : events ,
161+ }
0 commit comments