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 < #{expireTime}
+ </delete>
+
</mapper>
\ No newline at end of file
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]