@@ -56,29 +56,6 @@ def set_chromedriver_pid(self, pid: int) -> None:
5656 self .last_chromedriver_pid = pid
5757
5858
59- def cleanup_old_processes (debug_logger : Optional ["DebugLogger" ] = None ) -> None :
60- """Find and terminate any lingering chromedriver processes from previous runs.
61-
62- This is a safeguard against resource leaks from crashed/orphaned sessions.
63- """
64- print ("Running pre-emptive cleanup of old chromedriver processes..." )
65- if debug_logger :
66- debug_logger .log ("cleanup_old_processes: START" )
67- try :
68- # Use pkill to find and kill processes by name. -f checks the full command line.
69- # The [c]haracter class is a trick to prevent pkill from finding its own process.
70- command = "pkill -f '[c]hromedriver'"
71- result = subprocess .run (command , shell = True , check = False )
72- if debug_logger :
73- rc = getattr (result , "returncode" , "NA" )
74- debug_logger .log (f"cleanup_old_processes: END (rc={ rc } )" )
75- print ("Cleanup complete." )
76- except Exception as e :
77- if debug_logger :
78- debug_logger .log (f"cleanup_old_processes: ERROR { e } " )
79- print (f"Notice: Pre-emptive cleanup failed. This is non-critical. Error: { e } " )
80-
81-
8259def log_running_chromedriver_processes (debug_logger : DebugLogger ) -> None :
8360 """Logs any active chromedriver processes using `ps`.
8461
@@ -102,52 +79,64 @@ def log_running_chromedriver_processes(debug_logger: DebugLogger) -> None:
10279 debug_logger .log (f"Error while checking chromedriver processes: { e } " )
10380
10481
82+ def cleanup_old_processes () -> None :
83+ """Kill lingering chromedriver processes from prior runs (best-effort)."""
84+ try :
85+ subprocess .run ("pkill -f '[c]hromedriver'" , shell = True , check = False )
86+ except Exception :
87+ # Ignore any error; this is a best-effort cleanup.
88+ pass
89+
90+
10591@contextmanager
10692def managed_webdriver_session (chrome_options : Options , debug_logger : DebugLogger ):
107- """A self-cleaning context manager for the Selenium WebDriver.
93+ """A self-contained, resilient context manager for Selenium WebDriver.
10894
109- Sets up the driver and guarantees the chromedriver service process is
110- terminated on exit, aggressively if needed to avoid orphans.
95+ It handles pre-emptive cleanup, robust initialization, and guaranteed teardown.
11196 """
112- service : ChromeService = ChromeService ()
97+ debug_logger .log ("managed_webdriver_session: START" )
98+ print ("Running pre-emptive cleanup of old chromedriver processes..." )
99+ try :
100+ subprocess .run ("pkill -f '[c]hromedriver'" , shell = True , check = False )
101+ print ("Cleanup complete." )
102+ except Exception as e :
103+ print (f"Notice: Pre-emptive cleanup failed. This is non-critical. Error: { e } " )
104+
113105 driver : Optional [WebDriver ] = None
106+ service : Optional [ChromeService ] = None
114107 print ("Setting up WebDriver for gateway tests..." )
115108 try :
109+ service = ChromeService ()
116110 driver = webdriver .Chrome (service = service , options = chrome_options )
117- # Track and log the chromedriver PID if available
118- try :
119- if service and service .process and service .process .pid :
120- debug_logger .set_chromedriver_pid (service .process .pid )
121- debug_logger .log (
122- f"WebDriver service started with PID: { service .process .pid } "
123- )
124- except Exception as e : # pragma: no cover - best effort logging
125- debug_logger .log (f"Unable to retrieve WebDriver PID: { e } " )
111+ if service and service .process and service .process .pid :
112+ debug_logger .set_chromedriver_pid (service .process .pid )
113+ debug_logger .log (f"WebDriver service started with PID: { service .process .pid } " )
126114 yield driver
115+ except Exception as e :
116+ print (f"CRITICAL: Failed to initialize WebDriver session. Error: { e } " )
117+ yield None
127118 finally :
128119 print ("Shutting down WebDriver session..." )
129120 if driver :
130121 debug_logger .log ("WebDriver quit: START" )
131122 try :
132- driver .quit () # Graceful shutdown of browser and driver
123+ driver .quit ()
133124 finally :
134125 debug_logger .log ("WebDriver quit: END" )
135- # Aggressive kill of chromedriver service process
136126 if service and getattr (service , "process" , None ):
137- pid = getattr (service .process , "pid" , None )
138- if pid :
139- debug_logger .log (
140- f"Forcefully terminating chromedriver service (PID: { pid } )..."
141- )
142127 try :
143- service .process .kill () # Force kill to prevent orphans
144- service .process .wait (timeout = 5 ) # Confirm termination
145- debug_logger .log ("Service terminated successfully." )
146- except Exception as e : # pragma: no cover - defensive
147- debug_logger .log (
148- "Notice: Could not kill service process; it may have already exited. "
128+ pid = getattr (service .process , "pid" , None )
129+ if pid :
130+ print (f"Forcefully terminating chromedriver service (PID: { pid } )..." )
131+ service .process .kill ()
132+ service .process .wait (timeout = 5 )
133+ print ("Service terminated successfully." )
134+ except Exception as e :
135+ print (
136+ "Notice: Could not kill service process, it may have already exited. "
149137 f"Error: { e } "
150138 )
139+ debug_logger .log ("managed_webdriver_session: END" )
151140 # Verify process state after teardown
152141 log_running_chromedriver_processes (debug_logger )
153142
@@ -451,11 +440,8 @@ def run_ping_test_task(driver: WebDriver) -> Optional[GatewayPingResults]:
451440 return None
452441 return parse_gateway_ping_results (results_text )
453442 except Exception as e :
454- print (f"Error during gateway ping test: { e } " )
455- error_time = datetime .now ().strftime ("%Y%m%d_%H%M%S" )
456- screenshot_file = f"error_screenshot_gateway_ping_{ error_time } .png"
457- driver .save_screenshot (screenshot_file )
458- print (f"Saved screenshot to { screenshot_file } for debugging." )
443+ # Just log the error and return. Don't try to interact with a potentially dead driver.
444+ print (f"An error occurred during the task: { e } " )
459445 return None
460446
461447
@@ -504,7 +490,8 @@ def run_speed_test_task(driver: WebDriver, access_code: str) -> Optional[SpeedRe
504490 break
505491 return results if results else None
506492 except Exception as e :
507- print (f"Error during gateway speed test: { e } " )
493+ # Just log the error and return. Don't try to interact with a potentially dead driver.
494+ print (f"An error occurred during the task: { e } " )
508495 return None
509496
510497
@@ -713,14 +700,14 @@ def perform_checks() -> None:
713700 master_results : dict [str , str | float | int | None ] = {}
714701 debug_log = DebugLogger (start_time = time .time ())
715702 debug_log .log ("perform_checks: START" )
716- # Pre-emptive scavenger to ensure no orphaned chromedriver processes linger
717- cleanup_old_processes (debug_log )
718703 print (
719704 f"\n [{ datetime .now ().strftime ('%Y-%m-%d %H:%M:%S' )} ] "
720705 f"Starting checks (Run #{ run_counter } )..."
721706 )
722707
723- # Check for any lingering chromedriver processes from previous runs
708+ # Pre-emptive cleanup should run first
709+ cleanup_old_processes ()
710+ # Optionally log existing chromedriver processes after cleanup in debug mode
724711 log_running_chromedriver_processes (debug_log )
725712
726713 # --- Run Local Tests (No Browser Required) ---
@@ -763,34 +750,20 @@ def perform_checks() -> None:
763750 chrome_options .add_argument ("--no-sandbox" )
764751 chrome_options .add_argument ("--disable-dev-shm-usage" )
765752
766- try :
767- debug_log .log ("Selenium setup: START" )
768- with managed_webdriver_session (chrome_options , debug_log ) as driver :
769- debug_log .log ("Selenium setup: END" )
770- driver .get (config .GATEWAY_URL )
771- time .sleep (2 )
753+ # The 'try...except' is removed, as the context manager handles its own errors.
754+ with managed_webdriver_session (chrome_options , debug_log ) as driver :
755+ if driver :
756+ # Safely run tasks if the driver was created successfully
772757 debug_log .log ("run_ping_test_task: START" )
773- gateway_ping_results = run_ping_test_task (driver )
758+ master_results . update ( run_ping_test_task (driver ) or {} )
774759 debug_log .log ("run_ping_test_task: END" )
775- if gateway_ping_results :
776- master_results .update (gateway_ping_results )
777760 if should_run_gateway_speed_test :
778761 debug_log .log ("run_speed_test_task: START" )
779- gateway_speed_results = run_speed_test_task (driver , DEVICE_ACCESS_CODE )
762+ master_results . update ( run_speed_test_task (driver , DEVICE_ACCESS_CODE ) or {} )
780763 debug_log .log ("run_speed_test_task: END" )
781- if gateway_speed_results :
782- master_results .update (gateway_speed_results )
783- except Exception as e :
784- print (f"A critical error occurred in the WebDriver session: { e } " )
785- # Best-effort screenshot if driver existed during context
786- try :
787- if 'driver' in locals () and driver :
788- error_time = datetime .now ().strftime ("%Y%m%d_%H%M%S" )
789- screenshot_file = f"error_screenshot_{ error_time } .png"
790- driver .save_screenshot (screenshot_file )
791- print (f"Saved screenshot to { screenshot_file } for debugging." )
792- except Exception :
793- pass
764+ else :
765+ # This 'else' block will run if the context manager yields None
766+ print ("Skipping gateway tests because WebDriver session failed to start." )
794767
795768 debug_log .log ("perform_checks: END" )
796769 log_results (master_results )
0 commit comments