zmuxuny opened a new issue, #7152: URL: https://github.com/apache/rocketmq-dashboard/issues/7152
### Before Creating the Bug Report - [x] I have searched the [open issues](https://github.com/apache/rocketmq-dashboard/issues) of this repository and believe that this is not a duplicate. - [x] This is a defect in RocketMQ Studio, not a usage question and not a defect in another Apache RocketMQ repository. - [x] I can reproduce this on the current `master` branch, or I have stated the exact version I am running below. ### Studio Version rocketmq-studio at 127c47b06a268cc74224d5f34c56ec7c36ac0d55. ### Runtime Environment Java 21.0.12.1, Maven 3.9.12, existing JUnit/Mockito tests. Reproduction runs the real AiRunService and registry with controlled repository query interleavings and deferred workers. ### Connected RocketMQ Cluster No live RocketMQ or provider needed. The invariant fails during admission, before agent work. The test models the existing UNIQUE(conversation_id, turn) constraint at the repository boundary; no live MySQL concurrency test is claimed. ### Build Toolchain Offline Maven using cached dependencies; Maven heap384MiB, test fork256MiB, one fork. ### Describe the Bug AiRunService.sendMessage checks for an active run before reading maxTurn. If one request's empty active lookup becomes stale while another request admits turn1, the delayed request then reads maxTurn1 and admits turn2. The existing unique turn key does not collide, so two QUEUED runs and live handles can own the same conversation. Each creates its own event sink despite the documented single-writer timeline assumption. ### Steps to Reproduce 1. Start request A and retain its empty findActiveByConversationId result. 2. Before returning that result to A, admit request B completely, leaving its worker queued. 3. Resume A. It reads the now-increased maxTurn, chooses the next distinct turn, and inserts successfully. 4. Inspect inserted rows: both turn1 and turn2 are QUEUED for the same conversation. The deterministic test invokes both real admission paths, models exact turn-key uniqueness and leaves workers deferred. ### What Did You Expect to See? Only one request is admitted while its run remains active; the other receives the existing409 busy refusal and does not persist a second user turn or register another worker. ### What Did You See Instead? The unchanged baseline fails with expected one active row, actual two QUEUED rows: IDs11/12, turns1/2. A second interleaving control, where both requests already chose the same turn before either insert, passes through the existing unique-key-to-409 handling. Result:2 tests,1 assertion failure,0 errors,1 passing control. ### Additional Context A bounded correction is to read the candidate turn before checking active state. Seeing the winner's turn makes the subsequent active lookup refuse it; not seeing it makes both requests claim the same next turn, where the existing unique key rejects one. No new lock, API, schema or transaction is required. All-state searches found no equivalent fix; nearby #5755/#5761 concern terminal-state races, #5678 tests repository queries, and #6953/#6954 concern the separate deletion barrier. This report does not claim to fix concurrent conversation deletion. ### Are You Willing to Submit a Pull Request? - [x] Yes, I am willing to submit a pull request. -- 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]
