diff --git a/langfuse/batch_evaluation.py b/langfuse/batch_evaluation.py index 4d7bf3371..3e7540a31 100644 --- a/langfuse/batch_evaluation.py +++ b/langfuse/batch_evaluation.py @@ -38,6 +38,9 @@ metadata, model, usage, prompt, metrics, trace_context. """ +# The v2 observations API scans for up to 45 s before it returns a page. +_OBSERVATIONS_FETCH_TIMEOUT_SECONDS = 60 + def _with_time_fields(fields: Optional[str]) -> str: """Add the ``time`` group, whose ``updatedAt`` picks the newest duplicate row.""" @@ -962,9 +965,7 @@ def build_resume_token() -> BatchEvaluationResumeToken: fields=fields, ) except Exception as e: - logger.error( - "Failed to fetch batch after %s retries: %s", max_retries, e - ) + logger.error("Failed to fetch batch: %s", e) return self._build_result( total_items_fetched=total_items_fetched, @@ -1117,7 +1118,10 @@ async def _fetch_batch_with_retry( limit=limit, cursor=cursor, filter=filter, - request_options={"max_retries": max_retries}, + request_options={ + "max_retries": max_retries, + "timeout_in_seconds": _OBSERVATIONS_FETCH_TIMEOUT_SECONDS, + }, ) return list(response.data), response.meta.cursor diff --git a/tests/unit/test_batch_evaluation.py b/tests/unit/test_batch_evaluation.py index f6c29f4f6..3f3265ba1 100644 --- a/tests/unit/test_batch_evaluation.py +++ b/tests/unit/test_batch_evaluation.py @@ -255,7 +255,10 @@ async def test_fetch_failure_returns_resume_token_for_failed_page(): assert resumed.completed is True assert set(resumed.item_evaluations) == {"obs-3", "obs-2", "obs-1", "obs-0"} - assert api.calls[-1]["request_options"] == {"max_retries": 3} + assert api.calls[-1]["request_options"] == { + "max_retries": 3, + "timeout_in_seconds": 60, + } @pytest.mark.asyncio