From 5cdb50d85fd9d7965779b10807ab2fd56a00416f Mon Sep 17 00:00:00 2001 From: ceki-plugin Date: Thu, 11 Jun 2026 13:47:40 +0000 Subject: [PATCH] fix(sdk): retry captcha-request on 422 'Session not active' race After rent() the back marks the session 'active' immediately, but the provider WS attach on the relay lands a few hundred ms later. Calling request-captcha in that window returns 422 'Session not active' from AgentCaptchaRequestController. Retry up to 5 times with backoff 0.5/1/2/4s when the 422 body matches 'Session not active'. Other 422 bodies (validation, 'not configured') are still treated as terminal. --- ceki_sdk/_browser.py | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/ceki_sdk/_browser.py b/ceki_sdk/_browser.py index 8bb0816..f28017e 100644 --- a/ceki_sdk/_browser.py +++ b/ceki_sdk/_browser.py @@ -569,14 +569,23 @@ async def _create_captcha_event( "acceptance_deadline_at": int(acceptance_timeout), "completion_deadline_at": int(completion_timeout), } - async with httpx.AsyncClient() as http: - resp = await http.post( - f"{self._client.api_url}/api/agent/sessions/{self._match.event_id}/captcha-request", - headers={**self._api_headers(), "Content-Type": "application/json"}, - json=body, - ) - resp.raise_for_status() - result = resp.json() + url = f"{self._client.api_url}/api/agent/sessions/{self._match.event_id}/captcha-request" + backoff = [0.5, 1.0, 2.0, 4.0] + last_resp = None + for delay in [0.0] + backoff: + if delay: + await asyncio.sleep(delay) + async with httpx.AsyncClient() as http: + resp = await http.post( + url, + headers={**self._api_headers(), "Content-Type": "application/json"}, + json=body, + ) + last_resp = resp + if resp.status_code != 422 or "Session not active" not in (resp.text or ""): + break + last_resp.raise_for_status() + result = last_resp.json() event_id = result.get("id") if not event_id: raise RuntimeError("captcha request did not return an id")