-
[OPIK-7050] [BE] fix: resolve ClickHouse query failures surfacing as IOException (#7199)
发布于
2026-06-23 08:41:03 +00:00 - [OPIK-7050] [BE] fix: resolve ClickHouse query failures surfacing as IOException
Two deterministic, request-scoped ClickHouse query failures returned 500s
(the ClickHouse client wraps server-side SQL errors as java.io.IOException):- KpiCardDAO.threads_filtered did not project number_of_messages, so a thread
KPI-card filter on it failed with UNKNOWN_IDENTIFIER (code 47). It is now
always projected (cheap). first_message/last_message are projected only when
a filter references them, since they aggregate full input/output payloads. - SpanDAO partial-update binding passed null usage map values into a
CAST(... 'Map(String, Int64)') (non-nullable value type), failing with
CANNOT_CONVERT_TYPE (code 70). Null values are now dropped, matching the
batch insert path.
Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com
- [OPIK-7050] [BE] fix: drop null usage values in cost calc; dedup usage binding
Addresses PR review (baz): null token counts also reached the cost-recalculation
path. CostService -> SpanCostCalculator reads usage via getOrDefault(key, 0), which
returns null for a key present with a null value, then NPEs unboxing it in
BigDecimal.valueOf(...).- CostService.calculateCost: sanitize usage (drop null values) before pricing —
covers the update cost gate/calc, bulk gate, batch insert, and bindCost paths. - SpanDAO: extract bindUsage(...) helper, removing the duplicated null-skip loop
from both update binders. - Test: span-update test now sets model+provider so the cost recalculation runs
with a null-valued usage key.
Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com
- [OPIK-7050] [BE] refactor: consolidate usage null-filtering into UsageUtils
Addresses PR review (baz): the null-value filter existed in three places
(CostService, SpanDAO.bindUsage, and the batch insert path), risking drift
between what ClickHouse stores and what the cost calculator sees.Extract UsageUtils.sanitizeUsage(Map) and reuse it in all three: the cost
calculator, the span batch insert, and the update binders.Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com
- [OPIK-7050] [BE] style: snake_case the usage CAST bind params
Addresses PR review (baz): rename the usage array bind params from camelCase
usageKeys/usageValues to usage_keys/usage_values to follow the ClickHouse
parameter-binding guideline (.agents/skills/opik-backend/clickhouse.md) and
match the snake_case names already used by the partial-insert path. Placeholders
in UPDATE/PARTIAL_INSERT/BULK_UPDATE and the bindUsage() binds are renamed in sync.Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com
Co-authored-by: Claude Opus 4.8 (1M context) noreply@anthropic.com
下载附件