-
[OPIK-6968] [BE] perf: bulk thread resolve/create + scope open/close locks to non-idempotent ops (#7138)
发布于
2026-06-18 10:42:35 +00:00 - [OPIK-6968] [BE] perf: bulk thread resolve/create + scope open/close locks to non-idempotent ops
Builds on #7121/#7131, which already removed the per-project trace-threads lock from the two heaviest acquirers — trace ingestion and the online-scoring writes — so the lock no longer contends with ingestion or online scoring. What remains (open/close) is low-frequency, so this keeps a per-project lock there (a per-thread lock would mean N locks + N DB round-trips per batch — far more expensive than one bulk op under one lock) and instead tightens what runs under it.
openThread: resolve the thread id (idempotent get-or-create) outside the lock; lock only the status flip.
closeThreads: lock only the non-idempotent closure write; the post-close read (idempotent) and the online-scoring publish run outside the lock.
verifyAndCreateThreadIfNeed: fully bulk — one bulk get-or-create of thread-model ids (batch INSERT + constraint-violation retry in a fresh tx), one bulk existence check, one batch save + a single TraceThreadsCreated event — instead of ~3N sequential round-trips and N events.
Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com
- [OPIK-6968] [BE] fix: resolve+validate project ⇒ workspace inside open/close thread service
project_trace_threads has no workspace_id, so the project must be validated against the caller's workspace before any thread write. Move identifier resolution + workspace/visibility validation out of TracesResource and into TraceThreadService.openThread/closeThreads via the reactive projectService.resolveProjectIdAndVerifyVisibility (no blocking call on the reactive chain), so the write layer self-enforces it regardless of caller.
Add integration tests asserting open/close thread with a projectId from another workspace returns 404.
Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com
- [OPIK-6968] [BE] chore: address review — DRY DAO, rename, drop redundant NonNull, javadoc, test
-
TraceThreadIdDAO: DRY single save/find by delegating to the List flavour (default methods); single SqlUpdate/SqlQuery removed.
-
TraceThreadIdService.getOrCreateTraceThreadIds: drop NonNull on workspaceId (blank-checked) and threadIdToTimestamp (use MapUtils.isEmpty); add javadoc explaining the (project_id, thread_id) conflict + retry.
-
TraceThreadService: rename lambda 'id' -> 'verifiedProjectId' in open/closeThreads for readability.
-
Add IT: close thread that belongs to a different project in the same workspace -> 404.
Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com
- [OPIK-6968] [BE] chore: address review nits (Optional, isNotBlank, log workspace, dedupe criterion)
-
findByProjectIdAndThreadId returns Optional; callers use orElse(null).
-
Use StringUtils.isNotBlank instead of !isBlank.
-
Include workspaceId in the resolve-failure ErrorMessage, via .formatted().
-
Dedupe needIds keeping the earliest createdAt instead of an arbitrary pick.
Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com
Co-authored-by: Claude Opus 4.8 (1M context) noreply@anthropic.com
下载附件