4 changed files with 139 additions and 0 deletions
@ -0,0 +1,14 @@ |
|||||
|
package com.project.base.config; |
||||
|
|
||||
|
|
||||
|
import lombok.Data; |
||||
|
import org.springframework.boot.context.properties.ConfigurationProperties; |
||||
|
import org.springframework.stereotype.Component; |
||||
|
|
||||
|
@Data |
||||
|
@Component |
||||
|
@ConfigurationProperties(prefix = "scheduled-task") |
||||
|
public class ScheduledTaskProperties { |
||||
|
private String owner = "dev"; |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,19 @@ |
|||||
|
package com.project.question.config; |
||||
|
|
||||
|
import lombok.Data; |
||||
|
import org.springframework.boot.context.properties.ConfigurationProperties; |
||||
|
import org.springframework.stereotype.Component; |
||||
|
|
||||
|
@Data |
||||
|
@Component |
||||
|
@ConfigurationProperties(prefix = "question.replenish-inventory") |
||||
|
public class QuestionReplenishProperties { |
||||
|
// 闲时开始
|
||||
|
private int offPeakStart = 21; |
||||
|
// 闲时结束
|
||||
|
private int offPeakEnd = 8; |
||||
|
// 忙时间隔
|
||||
|
private int busyInterval = 30; |
||||
|
// 闲时间隔
|
||||
|
private int offPeakInterval = 180; |
||||
|
} |
||||
@ -0,0 +1,104 @@ |
|||||
|
package com.project.question.domain.job; |
||||
|
|
||||
|
import com.project.base.config.ScheduledTaskProperties; |
||||
|
import com.project.question.config.QuestionReplenishProperties; |
||||
|
import com.project.question.domain.service.QuestionInventoryDomainService; |
||||
|
import com.project.task.domain.entity.TaskEntity; |
||||
|
import com.project.task.mapper.TaskMapper; |
||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
||||
|
import jakarta.annotation.Resource; |
||||
|
import lombok.extern.slf4j.Slf4j; |
||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||
|
import org.springframework.scheduling.annotation.Scheduled; |
||||
|
import org.springframework.stereotype.Component; |
||||
|
|
||||
|
import java.time.LocalTime; |
||||
|
import java.util.Date; |
||||
|
import java.util.List; |
||||
|
import java.util.concurrent.CompletableFuture; |
||||
|
import java.util.concurrent.Executor; |
||||
|
import java.util.concurrent.atomic.AtomicLong; |
||||
|
|
||||
|
@Component |
||||
|
@Slf4j |
||||
|
public class InventoryCheckJob { |
||||
|
|
||||
|
@Autowired |
||||
|
private ScheduledTaskProperties taskProps; // 基础配置:判定 owner
|
||||
|
|
||||
|
@Autowired |
||||
|
private QuestionReplenishProperties replenishProps; // 业务配置:判定频率
|
||||
|
|
||||
|
@Autowired |
||||
|
private TaskMapper taskMapper; |
||||
|
|
||||
|
@Autowired |
||||
|
private QuestionInventoryDomainService questionInventoryDomainService; |
||||
|
|
||||
|
@Resource(name = "questionGenExecutor") |
||||
|
private Executor questionGenExecutor; |
||||
|
|
||||
|
// 记录累计经过的总分钟数
|
||||
|
private final AtomicLong elapsedMinutes = new AtomicLong(0); |
||||
|
|
||||
|
/** |
||||
|
* 每 10 分钟心跳一次 |
||||
|
*/ |
||||
|
@Scheduled(fixedRate = 600000) |
||||
|
public void run() { |
||||
|
|
||||
|
if ("dev".equalsIgnoreCase(taskProps.getOwner())) { |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
long currentTotalMinutes = elapsedMinutes.addAndGet(10); |
||||
|
int requiredInterval = getRequiredInterval(); |
||||
|
|
||||
|
|
||||
|
if (currentTotalMinutes % requiredInterval != 0) { |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
log.info(">>> [定时补库] 周期命中。当前时间段策略: {}min/次, 开始扫描任务", requiredInterval); |
||||
|
|
||||
|
List<TaskEntity> activeTasks = taskMapper.selectList( |
||||
|
new LambdaQueryWrapper<TaskEntity>() |
||||
|
.select(TaskEntity::getId) // 保护 Inode: 只查 ID
|
||||
|
.gt(TaskEntity::getEndTime, new Date()) |
||||
|
.eq(TaskEntity::getDeleted, false) |
||||
|
); |
||||
|
|
||||
|
if (activeTasks.isEmpty()) return; |
||||
|
|
||||
|
activeTasks.forEach(task -> |
||||
|
CompletableFuture.runAsync(() -> { |
||||
|
try { |
||||
|
questionInventoryDomainService.checkAndReplenish(task.getId()); |
||||
|
} catch (Exception e) { |
||||
|
throw new RuntimeException(e); |
||||
|
} |
||||
|
}, questionGenExecutor).exceptionally(ex -> { |
||||
|
log.error(">>> [定时补库] 任务[{}]检查失败", task.getId(), ex); |
||||
|
return null; |
||||
|
}) |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 判定忙闲时逻辑 |
||||
|
*/ |
||||
|
private int getRequiredInterval() { |
||||
|
int hour = LocalTime.now().getHour(); |
||||
|
int start = replenishProps.getOffPeakStart(); |
||||
|
int end = replenishProps.getOffPeakEnd(); |
||||
|
|
||||
|
boolean isOffPeak; |
||||
|
if (start > end) { // 跨天情况,如 23点到次日8点
|
||||
|
isOffPeak = (hour >= start || hour < end); |
||||
|
} else { // 当天情况,如 1点到5点
|
||||
|
isOffPeak = (hour >= start && hour < end); |
||||
|
} |
||||
|
|
||||
|
return isOffPeak ? replenishProps.getOffPeakInterval() : replenishProps.getBusyInterval(); |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue