-
[OPIK-7396] [BE] fix: tolerate >1 emitted row in TraceDAO.findById (get-by-id 500) (#7532)
发布于
2026-07-21 15:00:05 +00:00 - [OPIK-7396] [BE] fix: tolerate >1 emitted row in TraceDAO.findById
GET /v1/private/traces/{id} 500s with IndexOutOfBoundsException ("Source emitted
more than one item") when the assembled get-by-id query fans out to >1 row for the
id. findById reduced with singleOrEmpty(), which throws on >1. Use next() so the
first row is returned and the empty case still maps to 404.Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com
- [OPIK-7396] [BE] log when get-by-id resolves to >1 row
Replace next() with collectList()+first so we can emit a WARN (trace id + row
count) when the get-by-id query fans out to more than one row, keeping the
underlying duplication observable instead of silently dropping the extra rows.
Behaviour is unchanged: empty -> 404, otherwise the first row is returned.Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com
- [OPIK-7396] [BE] include workspace in get-by-id >1-row WARN
Read WORKSPACE_ID from the reactive context (as findByIds does) so the fan-out
WARN carries both the trace id and the workspace, making the duplication easier
to attribute. No behavioural change.Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com
- [OPIK-7396] [BE] test: cover get-by-id >1-row reducer
Extract the get-by-id row reduction into a package-private static
(firstOrLogFanOut) and unit-test it: empty -> empty, single -> that row, and1 -> first row without throwing IndexOutOfBoundsException. Pure unit test, no
DB harness.Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com
- [OPIK-7396] [BE] fix at source: collapse experiments_agg to one row per trace
The get-by-id 500 (and the reducer's non-deterministic experiment pick) came from
SELECT_BY_IDS fanning a trace into one row per experiment: the outer
LEFT JOIN experiments_agg had no per-trace dedup. Collapse experiments_agg to a
single canonical row per trace_id (most recent experiment by UUIDv7-ordered id) so
the trace-by-id join returns exactly one row. Also fixes batch getByIds returning
duplicate rows for multi-experiment traces. The findById reducer stays as a
defensive detector (logs + returns first if a fan-out ever reappears).Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com
- [OPIK-7396] [BE] Address review: @VisibleForTesting + log values at end
- Annotate firstOrLogFanOut with @VisibleForTesting (it exists for the unit test).
- Move the interpolated values to the end of the fan-out WARN (grep/service convention).
Kept collectList(): SELECT_BY_IDS now collapses experiments_agg to one row per id, so
the reducer buffers at most one row; it remains only as a defensive fan-out detector.
Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com
Co-authored-by: Claude Opus 4.8 (1M context) noreply@anthropic.com
下载附件