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/config/XxlJobConfig.java b/axzo-log-server/src/main/java/cn/axzo/log/platform/server/config/XxlJobConfig.java
new file mode 100644
index 0000000..71a4f67
--- /dev/null
+++ b/axzo-log-server/src/main/java/cn/axzo/log/platform/server/config/XxlJobConfig.java
@@ -0,0 +1,67 @@
+package cn.axzo.log.platform.server.config;
+
+import cn.azxo.framework.common.annotation.OnlyPodsEnvironment;
+import com.xxl.job.core.executor.impl.XxlJobSpringExecutor;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ *
+ * @author chenwenjian
+ * @version 1.0
+ * @date 2025/1/9 15:35
+ */
+@OnlyPodsEnvironment
+@Configuration(value = "xxlJobConfig")
+public class XxlJobConfig {
+
+ Logger logger = LoggerFactory.getLogger(XxlJobConfig.class);
+
+ /**
+ * //@Value("http://dev-xxl-job.axzo.cn/xxl-job-admin")
+ */
+ @Value("${xxl.job.admin.addresses}")
+ private String adminAddresses;
+
+ @Value("${xxl.job.executor.appname}")
+ private String appName;
+
+ @Value("")
+ private String ip;
+
+ @Value("${xxl.job.executor.port}")
+ private int port;
+
+
+ /**
+ * // @Value("${xxl.job.accessToken}")
+ */
+ @Value("")
+ private String accessToken;
+
+ @Value("")
+ private String logPath;
+
+ @Value("-1")
+ private int logRetentionDays;
+
+ @Bean
+ public XxlJobSpringExecutor xxlJobExecutor() {
+ logger.info(">>>>>>>>>>> xxl-job config init.");
+ XxlJobSpringExecutor xxlJobSpringExecutor = new XxlJobSpringExecutor();
+ xxlJobSpringExecutor.setAdminAddresses(adminAddresses);
+ xxlJobSpringExecutor.setAppname(appName);
+ xxlJobSpringExecutor.setIp(ip);
+ xxlJobSpringExecutor.setPort(port);
+ xxlJobSpringExecutor.setAccessToken(accessToken);
+ xxlJobSpringExecutor.setLogPath(logPath);
+ xxlJobSpringExecutor.setLogRetentionDays(logRetentionDays);
+
+ return xxlJobSpringExecutor;
+ }
+
+}
+
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..e8ab4b6
--- /dev/null
+++ b/axzo-log-server/src/main/java/cn/axzo/log/platform/server/job/LogCleanupJob.java
@@ -0,0 +1,104 @@
+package cn.axzo.log.platform.server.job;
+
+import cn.axzo.log.platform.server.entity.LogEntity;
+import com.alibaba.fastjson.JSON;
+import com.mongodb.client.result.DeleteResult;
+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.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.text.SimpleDateFormat;
+import java.util.Date;
+
+/**
+ * 清理日志
+ *
+ * @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":15,"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. error info: {}", e.getMessage());
+ }
+ 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.limit(paramDTO.getBatchSize());
+
+ SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
+ while (true) {
+ DeleteResult result = mongoTemplate.remove(query, LogEntity.class);
+ if (result.getDeletedCount() == 0) {
+ break;
+ }
+ deletedCount += result.getDeletedCount();
+ log.info("Cleaned up {} logs for scene: {} before data: {}", result.getDeletedCount(), paramDTO.getScene(), format.format(cutoffDate));
+ }
+ } 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 {
+
+ /**
+ * 每次删除的日志数量(页大小)
+ */
+ @Builder.Default
+ private int batchSize = 1000;
+
+ /**
+ * 保留天数
+ */
+ @Builder.Default
+ private int daysToKeep = 30;
+
+ /**
+ * 场景
+ */
+ @Builder.Default
+ private String scene = "networkLog";
+ }
+}