This is an automated email from the ASF dual-hosted git repository.

lizhimins pushed a commit to branch rocketmq-studio
in repository https://gitbox.apache.org/repos/asf/rocketmq-dashboard.git


The following commit(s) were added to refs/heads/rocketmq-studio by this push:
     new b1561bde4 fix(ai): stamp gmt_modified when reporting run speed (#7048)
b1561bde4 is described below

commit b1561bde45204578032f84dbb4cfd550c1827b0d
Author: wizcraft_kris <[email protected]>
AuthorDate: Mon Oct 26 16:28:43 2026 +0800

    fix(ai): stamp gmt_modified when reporting run speed (#7048)
---
 .../rocketmq/studio/ops/ai/conversation/AiRunService.java      |  9 +++++++--
 .../rocketmq/studio/ops/ai/conversation/AiRunServiceTest.java  | 10 +++++++---
 .../rocketmq/studio/ops/ai/conversation/AiRunTestSupport.java  |  1 +
 3 files changed, 15 insertions(+), 5 deletions(-)

diff --git 
a/server/src/main/java/org/apache/rocketmq/studio/ops/ai/conversation/AiRunService.java
 
b/server/src/main/java/org/apache/rocketmq/studio/ops/ai/conversation/AiRunService.java
index 0d8787516..4f279ab0a 100644
--- 
a/server/src/main/java/org/apache/rocketmq/studio/ops/ai/conversation/AiRunService.java
+++ 
b/server/src/main/java/org/apache/rocketmq/studio/ops/ai/conversation/AiRunService.java
@@ -477,8 +477,12 @@ public class AiRunService {
      * the non-null columns the stale read still carries — {@code status}, 
{@code end_seq} and
      * {@code gmt_modified} — are written back over the terminal ones. The 
nullable terminal facts
      * (duration, tokens, finished_at) survive: MyBatis-Plus defaults to 
{@code FieldStrategy.NOT_NULL},
-     * so a null field never reaches the SET clause. Only the speed column is 
touched, the same
-     * partial-update shape {@code rememberRuntimeSession} uses.
+     * so a null field never reaches the SET clause. The write touches only 
the speed column and the
+     * bookkeeping timestamp, the same partial-update shape {@code 
rememberRuntimeSession} uses.
+     * {@code gmt_modified} is stamped explicitly, from the same service clock 
as every other write
+     * to the row: the column is declared {@code ON UPDATE CURRENT_TIMESTAMP}, 
so leaving it null
+     * would not leave it alone — the database would rewrite it in its session 
timezone, a different
+     * clock than the UTC cutoff the orphan sweep compares against.
      *
      * @throws BusinessException 404 when the run does not exist or belongs to 
somebody else
      */
@@ -488,6 +492,7 @@ public class AiRunService {
         RmqAiRun update = new RmqAiRun();
         update.setId(run.getId());
         update.setTokensPerSecond(tokensPerSecond);
+        update.setGmtModified(LocalDateTime.now(clock));
         runRepository.update(update);
         run.setTokensPerSecond(tokensPerSecond);
         return run;
diff --git 
a/server/src/test/java/org/apache/rocketmq/studio/ops/ai/conversation/AiRunServiceTest.java
 
b/server/src/test/java/org/apache/rocketmq/studio/ops/ai/conversation/AiRunServiceTest.java
index 1aaf16866..bd35285ad 100644
--- 
a/server/src/test/java/org/apache/rocketmq/studio/ops/ai/conversation/AiRunServiceTest.java
+++ 
b/server/src/test/java/org/apache/rocketmq/studio/ops/ai/conversation/AiRunServiceTest.java
@@ -43,6 +43,7 @@ import 
org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
 import java.time.Clock;
 import java.time.Duration;
 import java.time.Instant;
+import java.time.LocalDateTime;
 import java.time.ZoneOffset;
 import java.util.ArrayList;
 import java.util.List;
@@ -439,12 +440,15 @@ class AiRunServiceTest {
     }
 
     @Test
-    void reportSpeedShouldTouchOnlyTheSpeedColumnTest() {
+    void reportSpeedShouldStampGmtModifiedWithoutTouchingFinalizeColumnsTest() 
{
         // The client reports the speed as its stream closes, which also 
happens mid-run when the
         // connection drops while the run keeps executing. A full-row write 
read before the worker
         // finalises would race finalizeRun's terminal update and write the 
stale RUNNING state back
         // over it, resurrecting the run as active and locking the 
conversation with 409s until the
-        // orphan sweep reaps the row. The update must therefore carry only 
the id and the speed.
+        // orphan sweep reaps the row. The update must therefore carry only 
the id, the speed and
+        // the bookkeeping timestamp, stamped from the service clock — an 
unstamped partial update
+        // lets the DDL's ON UPDATE CURRENT_TIMESTAMP rewrite gmt_modified in 
the database session's
+        // timezone, which is not the clock the orphan cutoff is compared 
against.
         RmqAiRun running = AiRunTestSupport.run(RUN_ID, CONVERSATION_ID, 1, 
RunStatus.RUNNING);
         when(runRepository.findById(RUN_ID)).thenReturn(Optional.of(running));
 
@@ -462,7 +466,7 @@ class AiRunServiceTest {
         assertThat(update.getEndSeq()).isNull();
         assertThat(update.getInputTokens()).isNull();
         assertThat(update.getOutputTokens()).isNull();
-        assertThat(update.getGmtModified()).isNull();
+        
assertThat(update.getGmtModified()).isEqualTo(LocalDateTime.parse("2026-09-18T10:00:00"));
     }
 
     @Test
diff --git 
a/server/src/test/java/org/apache/rocketmq/studio/ops/ai/conversation/AiRunTestSupport.java
 
b/server/src/test/java/org/apache/rocketmq/studio/ops/ai/conversation/AiRunTestSupport.java
index 412c33101..b0a2ee519 100644
--- 
a/server/src/test/java/org/apache/rocketmq/studio/ops/ai/conversation/AiRunTestSupport.java
+++ 
b/server/src/test/java/org/apache/rocketmq/studio/ops/ai/conversation/AiRunTestSupport.java
@@ -362,6 +362,7 @@ final class AiRunTestSupport {
         copy.setErrorCode(run.getErrorCode());
         copy.setErrorMessage(run.getErrorMessage());
         copy.setTokensPerSecond(run.getTokensPerSecond());
+        copy.setGmtModified(run.getGmtModified());
         return copy;
     }
 

Reply via email to