diff --git a/axzo-log-server/pom.xml b/axzo-log-server/pom.xml
index c597ffa..28c8395 100644
--- a/axzo-log-server/pom.xml
+++ b/axzo-log-server/pom.xml
@@ -173,6 +173,10 @@
1.0.0-SNAPSHOT
compile
+
+ com.xuxueli
+ xxl-job-core
+
diff --git a/axzo-log-server/src/main/java/cn/axzo/log/platform/server/job/LogCleanupJob.java b/axzo-log-server/src/main/java/cn/axzo/log/platform/server/job/LogCleanupJob.java
new file mode 100644
index 0000000..9ddd3ab
--- /dev/null
+++ b/axzo-log-server/src/main/java/cn/axzo/log/platform/server/job/LogCleanupJob.java
@@ -0,0 +1,107 @@
+package cn.axzo.log.platform.server.job;
+
+import cn.axzo.log.platform.server.entity.LogEntity;
+import com.alibaba.fastjson.JSON;
+import com.xxl.job.core.biz.model.ReturnT;
+import com.xxl.job.core.handler.annotation.XxlJob;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.data.domain.Sort;
+import org.springframework.data.mongodb.core.MongoTemplate;
+import org.springframework.data.mongodb.core.query.Criteria;
+import org.springframework.data.mongodb.core.query.Query;
+import org.springframework.stereotype.Component;
+
+import java.util.Date;
+import java.util.List;
+
+/**
+ * 清理日志
+ *
+ * @author chenwenjian
+ * @version 1.0
+ * @date 2025/1/9 11:25
+ */
+@Slf4j
+@Component
+@RequiredArgsConstructor
+public class LogCleanupJob {
+
+ private final MongoTemplate mongoTemplate;
+
+ /**
+ * 清理日志
+ *
+ * @param param 示例:{\"batchSize\":1000,\"daysToKeep\":30,\"scene\":\"networkLog\"}
+ * @return
+ */
+ @XxlJob("logCleanupJobHandler")
+ public ReturnT cleanupLogs(String param) {
+ log.info("Starting log cleanup job with parameters: {}", param);
+ // 设置默认参数,默认清理scene为networkLog且时间超过30天的日志数据
+ ParamDTO paramDTO = ParamDTO.builder().build();
+ // 解析参数
+ try {
+ paramDTO = JSON.parseObject(param, ParamDTO.class);
+ } catch (Exception e) {
+ log.warn("Invalid parameter format, using default values.");
+ }
+ long deletedCount = 0;
+ try {
+ // 构建查询条件,删除指定场景且时间超过指定天数的日志数据
+ Date cutoffDate = new Date(System.currentTimeMillis() - (paramDTO.getDaysToKeep() * 24 * 60 * 60 * 1000L));
+ Criteria criteria = Criteria.where("scene").is(paramDTO.getScene())
+ .and("timestamp").lte(cutoffDate.getTime());
+ Query query = new Query(criteria);
+ query.with(Sort.by(Sort.Direction.DESC, "_id"));
+ query.limit(paramDTO.getBatchSize());
+
+ while (true) {
+ List logsToDelete = mongoTemplate.find(query, LogEntity.class);
+ if (logsToDelete.isEmpty()) {
+ break;
+ }
+
+ mongoTemplate.remove(query, LogEntity.class);
+ deletedCount += logsToDelete.size();
+ log.info("Cleaned up {} logs for scene: {} before timestamp: {}", logsToDelete.size(), paramDTO.getScene(), cutoffDate);
+
+ // 更新查询条件,使用最后一个日志的ID作为游标
+ LogEntity lastLog = logsToDelete.get(logsToDelete.size() - 1);
+ query.addCriteria(Criteria.where("_id").lt(lastLog.getId()));
+ }
+ } catch (Exception e) {
+ log.error("Error during log cleanup job", e);
+ return ReturnT.FAIL;
+ }
+
+ log.info("Ending log cleanup job, total cleaned up logs for scene {}: {}", paramDTO.getScene(), deletedCount);
+ return ReturnT.SUCCESS;
+ }
+
+ @Data
+ @Builder
+ @NoArgsConstructor
+ @AllArgsConstructor
+ private static class ParamDTO {
+
+ /**
+ * 每次删除的日志数量(页大小)
+ */
+ private int batchSize = 1000;
+
+ /**
+ * 保留天数
+ */
+ private int daysToKeep = 30;
+
+ /**
+ * 场景
+ */
+ private String scene = "networkLog";
+ }
+}