Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions py/src/braintrust/logger.py
Original file line number Diff line number Diff line change
Expand Up @@ -1389,6 +1389,22 @@ def _submit_logs_request(self, items: Sequence[LogItemWithMeta], max_request_siz
else:
resp_errmsg = str(error)

# 413 Payload Too Large: retrying with the same batch cannot succeed; skip backoff.
if error is None and resp is not None and resp.status_code == 413:
errmsg = (
f"log request failed. Elapsed time: {time.time() - start_time} seconds. "
f"Payload size: {payload_bytes}. Error: {resp_errmsg}"
)
if self.failed_publish_payloads_dir:
_HTTPBackgroundLogger._write_payload_to_dir(
payload_dir=self.failed_publish_payloads_dir, payload=dataStr
)
self._log_failed_payloads_dir()
if self.sync_flush:
raise Exception(errmsg)
print(errmsg, file=self.outfile)
return

is_retrying = i + 1 < self.num_tries
retrying_text = "" if is_retrying else " Retrying"
errmsg = f"log request failed. Elapsed time: {time.time() - start_time} seconds. Payload size: {payload_bytes}.{retrying_text} Error: {resp_errmsg}"
Expand Down
50 changes: 50 additions & 0 deletions py/src/braintrust/test_logger.py
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,56 @@ def test_init_with_saved_parameters_attaches_reference(self):
assert payload["parameters_version"] == "v1"


class TestHTTPBackgroundLoggerLogs3(TestCase):
def test_submit_logs_request_413_skips_retries(self) -> None:
"""Any 413 while publishing ``/logs3`` cannot succeed on retry with the same payload.

``sync_flush`` controls whether the terminal failure raises instead of printing.
"""
from braintrust.logger import (
LogItemWithMeta,
Logs3OverflowInputRow,
_HTTPBackgroundLogger,
)

item = LogItemWithMeta(
str_value="{}",
overflow_meta=Logs3OverflowInputRow(
object_ids={},
has_comment=False,
is_delete=False,
byte_size=2,
),
)
max_result = {"max_request_size": 10**9, "can_use_overflow": True}

for response_text in ("Request Too Long", "", "Payload Too Large"):
for sync_flush in (False, True):
with self.subTest(response_text=response_text, sync_flush=sync_flush):
mock_resp = MagicMock()
mock_resp.ok = False
mock_resp.status_code = 413
mock_resp.text = response_text

mock_conn = MagicMock()
mock_conn.post.return_value = mock_resp

bg = _HTTPBackgroundLogger(LazyValue(lambda: mock_conn, use_mutex=False))
bg.num_tries = 5
bg.sync_flush = sync_flush

with patch("braintrust.logger.time.sleep") as mock_sleep:
if sync_flush:
with self.assertRaises(Exception) as cm:
bg._submit_logs_request([item], max_result)
self.assertIn("413", str(cm.exception))
else:
bg._submit_logs_request([item], max_result)

self.assertEqual(mock_conn.post.call_count, 1)
mock_sleep.assert_not_called()


class TestLogger(TestCase):
def test_load_prompt_prefers_version_over_environment_for_project_slug(self):
mock_api_conn = MagicMock()
Expand Down