zjncs opened a new pull request, #5196:
URL: https://github.com/apache/rocketmq-dashboard/pull/5196
### Which Issue(s) This PR Fixes
- Fixes #<issue-id>
### Brief Description
`POST /api/ai/runs/{runId}/speed` is sent by the client exactly as its
stream closes (`persistRunSpeed` in `useAgentRun.ts` runs in `finishStream`,
"whichever way it ended"). Per the conversation architecture, a closed
connection does **not** end the run — the run keeps executing server-side — so
the report can also land mid-run, and even for a normally finishing run it
races the finalisation window.
`reportSpeed` used to read the full `rmq_ai_run` row, set `tokensPerSecond`,
and write the **whole row** back (`updateById` writes every non-null field). If
that read lands just before `AiRunExecutor.finalizeRun`'s step-3 row update and
the write lands just after it, the stale pre-terminal row overwrites the
terminal state:
- `status` regresses to `RUNNING`, so `findActiveByConversationId` keeps
matching the run and **every later turn of that conversation is refused with
409 "该会话已有正在进行的回答"** until the orphan sweep reaps the stale-active row;
- the terminal facts the worker had written — `duration_ms`,
`input/output_tokens`, `finished_at`, `stop_reason` — are permanently lost,
while the timeline already holds the terminal `run_status` event and
`run_finished` was already delivered live (exactly the row/timeline divergence
the subsystem docs say must not happen).
The fix writes only `id` + `tokens_per_second` (a partial update, the same
shape `rememberRuntimeSession` and `applyTurnToConversation` already use in
this file), so `updateById` cannot touch any column the finalisation path owns.
`AiRunTestSupport.copyOf` also snapshots `tokensPerSecond` now, so the
captured update rows carry the column this endpoint writes.
### How Did You Test This Change?
New test `reportSpeedShouldTouchOnlyTheSpeedColumnTest`: resolves a RUNNING
run, reports a speed, and asserts the single captured update carries only the
id and the speed — every finalisation-owned column (`status`, `stopReason`,
`finishedAt`, `durationMs`, `endSeq`, tokens, `gmtModified`) must be null so
`updateById` cannot write it.
```
$ mvn test -Dtest=AiRunServiceTest
Tests run: 21, Failures: 0 # 20 before; the new test fails on the
old full-row write
# (status = "RUNNING" is not null in
the captured update)
$ mvn test -Dtest='org.apache.rocketmq.studio.ops.ai.conversation.*Test'
Tests run: 195, Failures: 1 # the one failure is
AgentRunHandleStopTest#
#
stopShouldKillTheRealSubprocessAndItsGrandchildTest, which
# fails identically on pristine master
in my container
# (real-subprocess process-tree
semantics; unrelated)
```
### Checklist
- [x] One coherent change; unrelated modifications are not bundled in
- [x] Commit subject follows Conventional Commits (`feat:` / `fix:` /
`refactor:` / `chore:` / `docs:` / `perf:`)
- [x] Tests added or updated for non-trivial changes, test methods named
`...Test`
- [x] New UI text has both Chinese and English entries under `web/src/i18n/`
(no UI text changed)
- [x] Architecture constraints stay green (`mvn test` runs the ArchUnit
checks)
- [x] New source files carry the ASF license header (no new files)
- [x] Documentation touched where behaviour changed (internal race fix, no
documented behaviour change)
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]