mirror of
https://github.com/usestrix/strix.git
synced 2026-08-16 09:26:39 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d31d6fb6b8 |
@@ -38,21 +38,21 @@ _TRANSIENT_CONNECTION_NAMES = {
|
||||
|
||||
|
||||
def _start_attempts() -> int:
|
||||
raw = os.environ.get("STRIX_SANDBOX_START_ATTEMPTS")
|
||||
raw = os.environ.get("STRIX_E2B_BOOTSTRAP_ATTEMPTS")
|
||||
if raw is None:
|
||||
return _DEFAULT_START_ATTEMPTS
|
||||
try:
|
||||
attempts = int(raw)
|
||||
except ValueError:
|
||||
logger.warning(
|
||||
"Invalid STRIX_SANDBOX_START_ATTEMPTS=%r; using %d",
|
||||
"Invalid STRIX_E2B_BOOTSTRAP_ATTEMPTS=%r; using %d",
|
||||
raw,
|
||||
_DEFAULT_START_ATTEMPTS,
|
||||
)
|
||||
return _DEFAULT_START_ATTEMPTS
|
||||
if attempts < 1:
|
||||
logger.warning(
|
||||
"STRIX_SANDBOX_START_ATTEMPTS must be positive; using %d",
|
||||
"STRIX_E2B_BOOTSTRAP_ATTEMPTS must be positive; using %d",
|
||||
_DEFAULT_START_ATTEMPTS,
|
||||
)
|
||||
return _DEFAULT_START_ATTEMPTS
|
||||
@@ -88,7 +88,7 @@ def _is_transient_start_error(error: BaseException) -> bool:
|
||||
if name in _TRANSIENT_TIMEOUT_NAMES:
|
||||
return True
|
||||
if name in _TRANSIENT_CONNECTION_NAMES and (
|
||||
module.startswith(("httpcore", "httpx", "agents"))
|
||||
module.startswith(("httpcore", "httpx", "e2b", "agents"))
|
||||
or name in {"ConnectionError", "ConnectionResetError"}
|
||||
):
|
||||
return True
|
||||
@@ -119,12 +119,11 @@ async def start_session_with_retry(
|
||||
if session is not None:
|
||||
try:
|
||||
await client.delete(session)
|
||||
except Exception as teardown_error:
|
||||
except Exception: # noqa: BLE001
|
||||
logger.warning(
|
||||
"Failed to tear down sandbox after start failure; aborting retry",
|
||||
"Failed to tear down sandbox after start failure",
|
||||
exc_info=True,
|
||||
)
|
||||
raise exc from teardown_error
|
||||
transient = _is_transient_start_error(exc)
|
||||
if not transient or attempt == max_attempts:
|
||||
raise
|
||||
|
||||
@@ -33,10 +33,9 @@ class _FakeSession:
|
||||
|
||||
|
||||
class _FakeClient:
|
||||
def __init__(self, *, delete_error: BaseException | None = None) -> None:
|
||||
def __init__(self) -> None:
|
||||
self.created = 0
|
||||
self.deleted: list[_FakeSession] = []
|
||||
self.delete_error = delete_error
|
||||
|
||||
async def create(self) -> _FakeSession:
|
||||
self.created += 1
|
||||
@@ -55,8 +54,6 @@ class _FakeClient:
|
||||
|
||||
async def delete(self, session: _FakeSession) -> None:
|
||||
self.deleted.append(session)
|
||||
if self.delete_error is not None:
|
||||
raise self.delete_error
|
||||
|
||||
|
||||
async def test_transient_workspace_failure_retries_and_tears_down(
|
||||
@@ -93,28 +90,6 @@ async def test_non_transient_workspace_failure_does_not_retry() -> None:
|
||||
assert client.deleted == [session]
|
||||
|
||||
|
||||
async def test_teardown_failure_raises_original_error_without_retry() -> None:
|
||||
start_error = WorkspaceStartError(
|
||||
path=Path("/workspace"),
|
||||
cause=TimeoutError("transient transport timeout"),
|
||||
)
|
||||
teardown_error = RuntimeError("teardown failed")
|
||||
client = _FakeClient(delete_error=teardown_error)
|
||||
session = _FakeSession([start_error])
|
||||
|
||||
async def create_session() -> _FakeSession:
|
||||
client.created += 1
|
||||
return session
|
||||
|
||||
with pytest.raises(WorkspaceStartError) as caught:
|
||||
await start_session_with_retry(client, create_session, attempts=3)
|
||||
|
||||
assert caught.value is start_error
|
||||
assert caught.value.__cause__ is teardown_error
|
||||
assert client.created == 1
|
||||
assert client.deleted == [session]
|
||||
|
||||
|
||||
async def test_each_transient_attempt_is_torn_down(monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
client = _FakeClient()
|
||||
client.created = 0
|
||||
|
||||
Reference in New Issue
Block a user