2
2
import json
3
3
import os
4
4
import shutil
5
- import tempfile
6
5
import signal
7
6
import sys
7
+ import tempfile
8
8
import time
9
9
from pathlib import Path
10
10
from typing import Any , Literal , Optional
23
23
from .config import StagehandConfig , default_config
24
24
from .context import StagehandContext
25
25
from .llm import LLMClient
26
+ from .logging import StagehandLogger , default_log_handler
26
27
from .metrics import StagehandFunctionName , StagehandMetrics
27
28
from .page import StagehandPage
28
29
from .schemas import AgentConfig
29
30
from .utils import (
30
- StagehandLogger ,
31
31
convert_dict_keys_to_camel_case ,
32
- default_log_handler ,
33
32
make_serializable ,
34
33
)
35
34
@@ -47,7 +46,7 @@ class Stagehand:
47
46
48
47
# Dictionary to store one lock per session_id
49
48
_session_locks = {}
50
-
49
+
51
50
# Flag to track if cleanup has been called
52
51
_cleanup_called = False
53
52
@@ -193,7 +192,7 @@ def __init__(
193
192
raise ValueError (
194
193
"browserbase_project_id is required for BROWSERBASE env with existing session_id (or set BROWSERBASE_PROJECT_ID in env)."
195
194
)
196
-
195
+
197
196
# Register signal handlers for graceful shutdown
198
197
self ._register_signal_handlers ()
199
198
@@ -224,13 +223,16 @@ def __init__(
224
223
225
224
def _register_signal_handlers (self ):
226
225
"""Register signal handlers for SIGINT and SIGTERM to ensure proper cleanup."""
226
+
227
227
def cleanup_handler (sig , frame ):
228
228
# Prevent multiple cleanup calls
229
229
if self .__class__ ._cleanup_called :
230
230
return
231
231
232
232
self .__class__ ._cleanup_called = True
233
- print (f"\n [{ signal .Signals (sig ).name } ] received. Ending Browserbase session..." )
233
+ print (
234
+ f"\n [{ signal .Signals (sig ).name } ] received. Ending Browserbase session..."
235
+ )
234
236
235
237
try :
236
238
# Try to get the current event loop
@@ -252,11 +254,11 @@ def cleanup_handler(sig, frame):
252
254
def schedule_cleanup ():
253
255
task = asyncio .create_task (self ._async_cleanup ())
254
256
# Shield the task to prevent it from being cancelled
255
- shielded = asyncio .shield (task )
257
+ asyncio .shield (task )
256
258
# We don't need to await here since we're in call_soon_threadsafe
257
-
259
+
258
260
loop .call_soon_threadsafe (schedule_cleanup )
259
-
261
+
260
262
except Exception as e :
261
263
print (f"Error during signal cleanup: { str (e )} " )
262
264
sys .exit (1 )
0 commit comments