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