fix(clickhouse): skip failed batch line items in the spend sink too

A failed JSONL line is part of the aggregate aretrieve_batch row's
request counts; writing it its own spend_logs row inflated request
counts with the line-item flag on. Extend the batch line-item guard to
the failure handler (review finding) and pin both directions: a failed
line item writes no row, a genuine live failure still does.
This commit is contained in:
Yucheng He 2026-10-05 01:07:58 -07:00
parent 9ca41c9085
commit 9c71dae02e
2 changed files with 31 additions and 0 deletions

View file

@ -205,6 +205,10 @@ class ClickHouseSpendLogger(ClickHouseBatchLogger):
self._log(kwargs)
async def async_log_failure_event(self, kwargs, response_obj, start_time, end_time) -> None:
# Failed batch lines are part of the same aggregate row's request counts;
# per-line rows here would inflate spend-log request counts.
if is_batch_line_item_event(kwargs):
return
self._log(kwargs)
def _log(self, kwargs: Mapping[str, Any]) -> None:

View file

@ -579,6 +579,33 @@ async def test_batch_line_item_success_event_does_not_write_spend(monkeypatch: p
assert logger.log_queue[1]["call_type"] == "aretrieve_batch"
assert logger.log_queue[1]["request_id"] == "batch-1"
assert logger.log_queue[1]["spend"] == 0.0001032
# A FAILED batch line is still part of the aggregate row's request counts and
# must not add its own spend row; a genuine live failure still writes one.
await logger.async_log_failure_event(
{
"standard_logging_object": _minimal_payload("chatcmpl-line-2", status="failure", cost=0.0),
"call_type": "acompletion",
"litellm_params": {"batch_parent_id": "batch-1"},
},
None,
now,
now,
)
await logger.async_log_failure_event(
{
"standard_logging_object": _minimal_payload("chatcmpl-live-2", status="failure", cost=0.0),
"call_type": "acompletion",
"litellm_params": {},
},
None,
now,
now,
)
assert len(logger.log_queue) == 3
assert logger.log_queue[-1]["request_id"] == "chatcmpl-live-2"
assert logger.log_queue[-1]["status"] == "failure"
if logger._flush_task is not None:
logger._flush_task.cancel()