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

wangtao29 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ozhera.git


The following commit(s) were added to refs/heads/master by this push:
     new b73204cf feat: add the function of automatically deleting chat records 
upon expiration. (#630)
b73204cf is described below

commit b73204cf068efe524feab1eeca3b7162d3fadd28
Author: Xue <[email protected]>
AuthorDate: Thu Jan 29 16:02:40 2026 +0800

    feat: add the function of automatically deleting chat records upon 
expiration. (#630)
    
    Co-authored-by: xueshan <[email protected]>
---
 .../manager/mapper/MilogAiConversationMapper.java  |  8 +++
 .../manager/service/MilogAiAnalysisService.java    |  6 +++
 .../service/impl/MilogAiAnalysisServiceImpl.java   | 60 ++++++++++++++++++++++
 .../resources/mapper/MilogAiConversationMapper.xml |  5 ++
 4 files changed, 79 insertions(+)

diff --git 
a/ozhera-log/log-manager/src/main/java/org/apache/ozhera/log/manager/mapper/MilogAiConversationMapper.java
 
b/ozhera-log/log-manager/src/main/java/org/apache/ozhera/log/manager/mapper/MilogAiConversationMapper.java
index f6d6f157..b975c050 100644
--- 
a/ozhera-log/log-manager/src/main/java/org/apache/ozhera/log/manager/mapper/MilogAiConversationMapper.java
+++ 
b/ozhera-log/log-manager/src/main/java/org/apache/ozhera/log/manager/mapper/MilogAiConversationMapper.java
@@ -28,4 +28,12 @@ import java.util.List;
 @Mapper
 public interface MilogAiConversationMapper extends 
BaseMapper<MilogAiConversationDO> {
     List<MilogAiConversationDO> getListByUserAndStore(@Param(value = 
"storeId") Long storeId, @Param(value = "creator") String creator);
+
+    /**
+     * Delete conversations that have not been updated for more than the 
specified number of days
+     *
+     * @param expireTime the cutoff timestamp, conversations with update_time 
before this will be deleted
+     * @return the number of deleted records
+     */
+    int deleteByUpdateTimeBefore(@Param(value = "expireTime") Long expireTime);
 }
diff --git 
a/ozhera-log/log-manager/src/main/java/org/apache/ozhera/log/manager/service/MilogAiAnalysisService.java
 
b/ozhera-log/log-manager/src/main/java/org/apache/ozhera/log/manager/service/MilogAiAnalysisService.java
index 783040b1..c4e1a9f6 100644
--- 
a/ozhera-log/log-manager/src/main/java/org/apache/ozhera/log/manager/service/MilogAiAnalysisService.java
+++ 
b/ozhera-log/log-manager/src/main/java/org/apache/ozhera/log/manager/service/MilogAiAnalysisService.java
@@ -42,4 +42,10 @@ public interface MilogAiAnalysisService {
 
     Result<Boolean> closeAiAnalysis(Long id);
 
+    /**
+     * Clean up expired AI conversation records
+     * Deletes conversations that have not been updated for more than 7 days
+     */
+    void cleanExpiredConversations();
+
 }
diff --git 
a/ozhera-log/log-manager/src/main/java/org/apache/ozhera/log/manager/service/impl/MilogAiAnalysisServiceImpl.java
 
b/ozhera-log/log-manager/src/main/java/org/apache/ozhera/log/manager/service/impl/MilogAiAnalysisServiceImpl.java
index 07305ca1..d1c9a291 100644
--- 
a/ozhera-log/log-manager/src/main/java/org/apache/ozhera/log/manager/service/impl/MilogAiAnalysisServiceImpl.java
+++ 
b/ozhera-log/log-manager/src/main/java/org/apache/ozhera/log/manager/service/impl/MilogAiAnalysisServiceImpl.java
@@ -57,10 +57,13 @@ import java.time.Instant;
 import java.time.LocalDateTime;
 import java.time.ZoneId;
 import java.time.format.DateTimeFormatter;
+import java.time.temporal.ChronoUnit;
 import java.util.*;
 import java.util.concurrent.*;
 import java.util.concurrent.atomic.AtomicReference;
 
+import static java.util.concurrent.TimeUnit.MINUTES;
+
 
 @Slf4j
 @Service
@@ -86,10 +89,16 @@ public class MilogAiAnalysisServiceImpl implements 
MilogAiAnalysisService {
 
     private static final String GLOBAL_SHUTDOWN_LOCK_KEY = 
"milog.ai.shutdown:global";
 
+    private static final String GLOBAL_CLEAN_EXPIRED_LOCK_KEY = 
"milog.ai.cleanExpired:global";
+
+    private static final int CONVERSATION_EXPIRE_DAYS = 7;
+
     private static final Gson gson = new Gson();
 
     private static final ExecutorService executor = 
Executors.newVirtualThreadPerTaskExecutor();
 
+    private static final ScheduledExecutorService cleanupScheduler = 
Executors.newSingleThreadScheduledExecutor();
+
     private static final JedisCluster jedisCluster = 
RedisClientFactory.getJedisCluster();
 
     private static final Encoding TOKENIZER = 
Encodings.newDefaultEncodingRegistry().getEncoding(EncodingType.CL100K_BASE);
@@ -106,6 +115,17 @@ public class MilogAiAnalysisServiceImpl implements 
MilogAiAnalysisService {
         llm.setConfigFunction(llmProvider -> Optional.of(config));
         analysisBot.setLlm(llm);
         contentSimplifyBot.setLlm(llm);
+
+        // Schedule cleanup task to run at 3:00 AM every day
+        long initialDelay = calculateDelayToTargetHour(3);
+        cleanupScheduler.scheduleAtFixedRate(() -> {
+            try {
+                cleanExpiredConversations();
+            } catch (Exception e) {
+                log.error("Scheduled cleanup task failed", e);
+            }
+        }, initialDelay, 24 * 60, MINUTES);
+        log.info("Scheduled AI conversation cleanup task initialized, will run 
at 3:00 AM every day, initial delay: {} minutes", initialDelay);
     }
 
 
@@ -536,6 +556,28 @@ public class MilogAiAnalysisServiceImpl implements 
MilogAiAnalysisService {
         return Result.success(true);
     }
 
+    @Override
+    public void cleanExpiredConversations() {
+        // Use distributed lock to ensure only one instance executes the 
cleanup
+        if (!trySimpleLock(GLOBAL_CLEAN_EXPIRED_LOCK_KEY, 300L)) {
+            log.info("Another instance is already running 
cleanExpiredConversations, skipping...");
+            return;
+        }
+
+        try {
+            // Calculate the expiration timestamp (7 days ago)
+            long expireTime = Instant.now().minus(CONVERSATION_EXPIRE_DAYS, 
ChronoUnit.DAYS).toEpochMilli();
+
+            // Delete expired conversations from database
+            int deletedCount = 
milogAiConversationMapper.deleteByUpdateTimeBefore(expireTime);
+
+            log.info("Cleaned up {} expired AI conversation records 
(update_time before {})",
+                    deletedCount, timestampToStr(expireTime));
+        } catch (Exception e) {
+            log.error("Failed to clean expired AI conversations", e);
+        }
+    }
+
     private static String timestampToStr(long timestamp) {
         Instant instant = Instant.ofEpochMilli(timestamp);
         LocalDateTime dateTime = LocalDateTime.ofInstant(instant, 
ZoneId.systemDefault());
@@ -543,6 +585,24 @@ public class MilogAiAnalysisServiceImpl implements 
MilogAiAnalysisService {
         return dateTime.format(formatter);
     }
 
+    /**
+     * Calculate the delay in minutes from now to the target hour (e.g., 3:00 
AM)
+     *
+     * @param targetHour the target hour (0-23)
+     * @return delay in minutes
+     */
+    private static long calculateDelayToTargetHour(int targetHour) {
+        LocalDateTime now = LocalDateTime.now();
+        LocalDateTime targetTime = 
now.withHour(targetHour).withMinute(0).withSecond(0).withNano(0);
+
+        // If the target time has already passed today, schedule for tomorrow
+        if (now.isAfter(targetTime)) {
+            targetTime = targetTime.plusDays(1);
+        }
+
+        return ChronoUnit.MINUTES.between(now, targetTime);
+    }
+
     private Map<String, List<BotQAParam.QAParam>> getConversation(Long 
conversationId) {
         String redisKey = MILOG_AI_KEY_PREFIX + conversationId;
         String value = jedisCluster.get(redisKey);
diff --git 
a/ozhera-log/log-manager/src/main/resources/mapper/MilogAiConversationMapper.xml
 
b/ozhera-log/log-manager/src/main/resources/mapper/MilogAiConversationMapper.xml
index 3f78fc4e..85248d96 100644
--- 
a/ozhera-log/log-manager/src/main/resources/mapper/MilogAiConversationMapper.xml
+++ 
b/ozhera-log/log-manager/src/main/resources/mapper/MilogAiConversationMapper.xml
@@ -31,4 +31,9 @@ http://www.apache.org/licenses/LICENSE-2.0
         ORDER BY update_time DESC
     </select>
 
+    <delete id="deleteByUpdateTimeBefore">
+        DELETE FROM milog_ai_conversation
+        WHERE update_time &lt; #{expireTime}
+    </delete>
+
 </mapper>
\ No newline at end of file


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to