Skip to content

Commit 93cf7ca

Browse files
committed
interrupts enabled
1 parent 0d1fac8 commit 93cf7ca

File tree

2 files changed

+73
-1
lines changed

2 files changed

+73
-1
lines changed

stagehand/client.py

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import asyncio
22
import json
33
import logging
4+
import signal
5+
import sys
46
import time
57
from collections.abc import Awaitable
68
from typing import Any, Callable, Optional
@@ -29,6 +31,9 @@ class Stagehand(StagehandBase):
2931

3032
# Dictionary to store one lock per session_id
3133
_session_locks = {}
34+
35+
# Flag to track if cleanup has been called
36+
_cleanup_called = False
3237

3338
def __init__(
3439
self,
@@ -115,6 +120,9 @@ def __init__(
115120
raise ValueError(
116121
"browserbase_project_id is required (or set BROWSERBASE_PROJECT_ID in env)."
117122
)
123+
124+
# Register signal handlers for graceful shutdown
125+
self._register_signal_handlers()
118126

119127
def _get_lock_for_session(self) -> asyncio.Lock:
120128
"""
@@ -428,3 +436,40 @@ def _log(self, message: str, level: int = 1):
428436
logger.warning(formatted_msg)
429437
else:
430438
logger.debug(formatted_msg)
439+
440+
def _register_signal_handlers(self):
441+
"""Register signal handlers for SIGINT and SIGTERM to ensure proper cleanup."""
442+
def cleanup_handler(sig, frame):
443+
if self.__class__._cleanup_called:
444+
return
445+
446+
self.__class__._cleanup_called = True
447+
print(f"\n[{signal.Signals(sig).name}] received. Ending Browserbase session...")
448+
449+
try:
450+
# For more niceness, try to end the session synchronously
451+
if self.session_id:
452+
import requests
453+
headers = {
454+
"x-bb-api-key": self.browserbase_api_key,
455+
"x-bb-project-id": self.browserbase_project_id,
456+
"Content-Type": "application/json",
457+
}
458+
try:
459+
requests.post(
460+
f"{self.server_url}/sessions/{self.session_id}/end",
461+
json={"sessionId": self.session_id},
462+
headers=headers,
463+
timeout=3.0 # Short timeout to avoid hanging
464+
)
465+
print(f"Session {self.session_id} ended successfully")
466+
except Exception:
467+
# Ignore any errors during cleanup
468+
pass
469+
finally:
470+
# Just exit immediately with a successful status code
471+
sys.exit(0)
472+
473+
# Register signal handlers
474+
signal.signal(signal.SIGINT, cleanup_handler)
475+
signal.signal(signal.SIGTERM, cleanup_handler)

stagehand/sync/client.py

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
import json
22
import logging
3-
import time
43
from typing import Any, Callable, Optional
54

65
import requests
6+
import signal
7+
import sys
78
from playwright.sync_api import sync_playwright
89

910
from ..base import StagehandBase
@@ -58,6 +59,32 @@ def __init__(
5859
self._playwright_page = None
5960
self.model_client_options = model_client_options
6061
self.streamed_response = True # Default to True for streamed responses
62+
63+
# Register signal handlers for graceful shutdown
64+
self._register_signal_handlers()
65+
66+
def _register_signal_handlers(self):
67+
"""Register signal handlers for SIGINT and SIGTERM to ensure proper cleanup."""
68+
def cleanup_handler(sig, frame):
69+
if self.__class__._cleanup_called:
70+
return
71+
72+
self.__class__._cleanup_called = True
73+
print(f"\n[{signal.Signals(sig).name}] received. Ending Browserbase session...")
74+
75+
try:
76+
# For the sync client, we can directly call close()
77+
self.close()
78+
print(f"Session {self.session_id} ended successfully")
79+
except Exception as e:
80+
print(f"Error ending Browserbase session: {str(e)}")
81+
finally:
82+
# Exit explicitly once cleanup is done
83+
sys.exit(0)
84+
85+
# Register signal handlers
86+
signal.signal(signal.SIGINT, cleanup_handler)
87+
signal.signal(signal.SIGTERM, cleanup_handler)
6188

6289
def init(self):
6390
"""

0 commit comments

Comments
 (0)