发布

  • [OPIK-6968] [BE] perf: bulk thread resolve/create + scope open/close locks to non-idempotent ops (#7138)

    frostbyte_neo 发布于 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

    下载附件