123123213weqw opened a new pull request, #5758:
URL: https://github.com/apache/rocketmq-dashboard/pull/5758

   ## What\n\n`AgentStreamSession.finishReplay` flipped the session to LIVE and 
copied the buffered frames out under `sendLock`, but then drained them 
(`pending.forEach(deliver)`) **outside** the lock, with each frame's 
`sendAgent` re-taking the lock individually.\n\n## Why it is a bug\n\nA 
publisher thread (`AgentRunRegistry.publish` fan-out) that hands a live frame 
to the same session while the drain sits between two buffered frames contends 
for the lock per-frame, and can win it: the later frame reaches the wire before 
an older buffered one. The client folds frames in arrival order, so the 
transcript renders the later block ahead of the older one — a `tool_done` 
before its `tool_start`, an answer before the reasoning that preceded it. This 
window opens exactly at the replay-to-live handover, i.e. on every reconnect 
with frames in flight.\n\n## The fix\n\nDrain while holding `sendLock`. The 
intrinsic lock is reentrant, so `deliver`'s own `synchronized` blocks nest; a 
publisher no
 w parks until the whole drain finished, and arrival order on the wire is the 
buffer order followed by the live frames.\n\n## Test\n\nRed-first, in the new 
`AgentStreamSessionTest`: two frames are buffered during REPLAYING, and while 
the first is being written a second thread delivers a later frame (parked on 
the lock first, so the two threads genuinely race for it, repeated 50 times). 
Asserts the wire order is `older, newer, published` on every attempt — fails on 
the previous code (the later frame overtakes), passes with the drain under the 
lock. `AiStreamControllerTest` stays green.


-- 
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]

Reply via email to