feat: 2.4.0
1. 优化JOB下次触发时间不是最新的时间,导致计算的下次触发时间不准 2. 修复更新触发时间呢,为重新计算下次触发时间 3. 重试的扫描任务的拉取数据的次数使用动态计算耗时进行计算
This commit is contained in:
parent
fcf360bbdd
commit
171951f09a
@ -7,6 +7,9 @@ import java.util.List;
|
|||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
import java.util.function.LongConsumer;
|
||||||
|
import java.util.function.LongFunction;
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author: www.byteblogs.com
|
* @author: www.byteblogs.com
|
||||||
@ -18,14 +21,38 @@ public class PartitionTaskUtils {
|
|||||||
private PartitionTaskUtils() {
|
private PartitionTaskUtils() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static long process(LongFunction<List<? extends PartitionTask>> dataSource,
|
||||||
|
Consumer<List<? extends PartitionTask>> task,
|
||||||
|
long startId) {
|
||||||
|
return process(dataSource, task, curStartId -> {}, CollectionUtils::isEmpty, startId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static long process(LongFunction<List<? extends PartitionTask>> dataSource,
|
||||||
|
Consumer<List<? extends PartitionTask>> task,
|
||||||
|
Predicate<List<? extends PartitionTask>> stopCondition,
|
||||||
|
long startId) {
|
||||||
|
return process(dataSource, task, curStartId -> {}, stopCondition, startId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static long process(LongFunction<List<? extends PartitionTask>> dataSource,
|
||||||
|
Consumer<List<? extends PartitionTask>> task,
|
||||||
|
LongConsumer stopAfterProcessor,
|
||||||
|
long startId) {
|
||||||
|
return process(dataSource, task, stopAfterProcessor, CollectionUtils::isEmpty, startId);
|
||||||
|
}
|
||||||
|
|
||||||
public static long process(
|
public static long process(
|
||||||
Function<Long, List<? extends PartitionTask>> dataSource, Consumer<List<? extends PartitionTask>> task,
|
LongFunction<List<? extends PartitionTask>> dataSource,
|
||||||
|
Consumer<List<? extends PartitionTask>> task,
|
||||||
|
LongConsumer stopAfterProcessor,
|
||||||
|
Predicate<List<? extends PartitionTask>> stopCondition,
|
||||||
long startId) {
|
long startId) {
|
||||||
int total = 0;
|
int total = 0;
|
||||||
do {
|
do {
|
||||||
List<? extends PartitionTask> products = dataSource.apply(startId);
|
List<? extends PartitionTask> products = dataSource.apply(startId);
|
||||||
if (CollectionUtils.isEmpty(products)) {
|
if (stopCondition.test(products)) {
|
||||||
// 没有查询到数据直接退出
|
// 没有查询到数据直接退出
|
||||||
|
stopAfterProcessor.accept(startId);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -122,7 +122,12 @@ public class WaitStrategies {
|
|||||||
public LocalDateTime computeRetryTime(WaitStrategyContext context) {
|
public LocalDateTime computeRetryTime(WaitStrategyContext context) {
|
||||||
long triggerInterval = Long.parseLong(context.triggerInterval);
|
long triggerInterval = Long.parseLong(context.triggerInterval);
|
||||||
|
|
||||||
return context.getNextTriggerAt().plusSeconds(triggerInterval);
|
LocalDateTime nextTriggerAt = context.getNextTriggerAt();
|
||||||
|
if (nextTriggerAt.isBefore(LocalDateTime.now())) {
|
||||||
|
nextTriggerAt = LocalDateTime.now();
|
||||||
|
}
|
||||||
|
|
||||||
|
return nextTriggerAt.plusSeconds(triggerInterval);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -134,9 +139,14 @@ public class WaitStrategies {
|
|||||||
@Override
|
@Override
|
||||||
public LocalDateTime computeRetryTime(WaitStrategyContext context) {
|
public LocalDateTime computeRetryTime(WaitStrategyContext context) {
|
||||||
|
|
||||||
|
LocalDateTime nextTriggerAt = context.getNextTriggerAt();
|
||||||
|
if (nextTriggerAt.isBefore(LocalDateTime.now())) {
|
||||||
|
nextTriggerAt = LocalDateTime.now();
|
||||||
|
}
|
||||||
|
|
||||||
Date nextValidTime;
|
Date nextValidTime;
|
||||||
try {
|
try {
|
||||||
ZonedDateTime zdt = context.getNextTriggerAt().atZone(ZoneOffset.ofHours(8));
|
ZonedDateTime zdt = nextTriggerAt.atZone(ZoneOffset.ofHours(8));
|
||||||
nextValidTime = new CronExpression(context.getTriggerInterval()).getNextValidTimeAfter(Date.from(zdt.toInstant()));
|
nextValidTime = new CronExpression(context.getTriggerInterval()).getNextValidTimeAfter(Date.from(zdt.toInstant()));
|
||||||
} catch (ParseException e) {
|
} catch (ParseException e) {
|
||||||
throw new EasyRetryServerException("解析CRON表达式异常 [{}]", context.getTriggerInterval(), e);
|
throw new EasyRetryServerException("解析CRON表达式异常 [{}]", context.getTriggerInterval(), e);
|
||||||
|
@ -32,6 +32,9 @@ import java.util.List;
|
|||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
import java.util.concurrent.atomic.AtomicLong;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 数据扫描模板类
|
* 数据扫描模板类
|
||||||
@ -55,8 +58,8 @@ public abstract class AbstractScanGroup extends AbstractActor {
|
|||||||
@Autowired
|
@Autowired
|
||||||
protected List<TaskExecutor> taskExecutors;
|
protected List<TaskExecutor> taskExecutors;
|
||||||
|
|
||||||
private static long preCostTime = 0L;
|
private static final AtomicLong preCostTime = new AtomicLong(0L);
|
||||||
private static long loopCount = 1L;
|
private static final AtomicLong pullCount = new AtomicLong(1L);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Receive createReceive() {
|
public Receive createReceive() {
|
||||||
@ -74,8 +77,9 @@ public abstract class AbstractScanGroup extends AbstractActor {
|
|||||||
// 获取结束时间
|
// 获取结束时间
|
||||||
long endTime = System.nanoTime();
|
long endTime = System.nanoTime();
|
||||||
|
|
||||||
preCostTime = (endTime - startTime) / 1_000_000;
|
preCostTime.set((endTime - startTime) / 1_000_000);
|
||||||
log.info("重试任务调度耗时:[{}]", preCostTime);
|
|
||||||
|
log.info("重试任务调度耗时:[{}]", preCostTime.get());
|
||||||
|
|
||||||
}).build();
|
}).build();
|
||||||
|
|
||||||
@ -84,41 +88,43 @@ public abstract class AbstractScanGroup extends AbstractActor {
|
|||||||
protected void doScan(final ScanTask scanTask) {
|
protected void doScan(final ScanTask scanTask) {
|
||||||
|
|
||||||
// 计算循环拉取的次数
|
// 计算循环拉取的次数
|
||||||
if (preCostTime > 0) {
|
if (preCostTime.get() > 0) {
|
||||||
loopCount = (10 * 1000) / preCostTime;
|
long loopCount = Math.max((10 * 1000) / preCostTime.get(), 1);
|
||||||
loopCount = loopCount == 0 ? 1 : loopCount;
|
// TODO 最大拉取次数支持可配置
|
||||||
|
loopCount = Math.min(loopCount, 10);
|
||||||
|
pullCount.set(loopCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
String groupName = scanTask.getGroupName();
|
String groupName = scanTask.getGroupName();
|
||||||
Long lastId = Optional.ofNullable(getLastId(groupName)).orElse(0L);
|
Long lastId = Optional.ofNullable(getLastId(groupName)).orElse(0L);
|
||||||
|
|
||||||
|
log.info("retry scan start. groupName:[{}] startId:[{}] pullCount:[{}] preCostTime:[{}]",
|
||||||
|
groupName, lastId, pullCount.get(), preCostTime.get());
|
||||||
|
|
||||||
AtomicInteger count = new AtomicInteger(0);
|
AtomicInteger count = new AtomicInteger(0);
|
||||||
PartitionTaskUtils.process(startId -> {
|
PartitionTaskUtils.process(startId -> listAvailableTasks(groupName, startId, taskActuatorScene().getTaskType().getType()),
|
||||||
int i = count.getAndIncrement();
|
partitionTasks -> processRetryPartitionTasks(partitionTasks, scanTask), partitionTasks -> {
|
||||||
if (i > loopCount) {
|
if (CollectionUtils.isEmpty(partitionTasks)) {
|
||||||
// 为空则中断处理
|
putLastId(scanTask.getGroupName(), 0L);
|
||||||
return Lists.newArrayList();
|
return Boolean.TRUE;
|
||||||
}
|
}
|
||||||
return listAvailableTasks(groupName, startId, taskActuatorScene().getTaskType().getType());
|
|
||||||
},
|
// 超过最大的拉取次数则中断
|
||||||
partitionTasks -> processRetryPartitionTasks(partitionTasks, scanTask), lastId);
|
if (count.getAndIncrement() > pullCount.get()) {
|
||||||
|
putLastId(scanTask.getGroupName(), partitionTasks.get(partitionTasks.size() - 1).getId());
|
||||||
|
return Boolean.TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}, lastId);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void processRetryPartitionTasks(List<? extends PartitionTask> partitionTasks, ScanTask scanTask) {
|
private void processRetryPartitionTasks(List<? extends PartitionTask> partitionTasks, ScanTask scanTask) {
|
||||||
|
|
||||||
StopWatch watch = new StopWatch();
|
|
||||||
watch.start();
|
|
||||||
if (!CollectionUtils.isEmpty(partitionTasks)) {
|
|
||||||
putLastId(scanTask.getGroupName(), partitionTasks.get(partitionTasks.size() - 1).getId());
|
|
||||||
for (PartitionTask partitionTask : partitionTasks) {
|
for (PartitionTask partitionTask : partitionTasks) {
|
||||||
processRetryTask((RetryPartitionTask) partitionTask);
|
processRetryTask((RetryPartitionTask) partitionTask);
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
putLastId(scanTask.getGroupName(), 0L);
|
|
||||||
}
|
|
||||||
|
|
||||||
watch.getTotalTimeMillis();
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -131,7 +137,8 @@ public abstract class AbstractScanGroup extends AbstractActor {
|
|||||||
|
|
||||||
long delay = partitionTask.getNextTriggerAt().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli()
|
long delay = partitionTask.getNextTriggerAt().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli()
|
||||||
- System.currentTimeMillis();
|
- System.currentTimeMillis();
|
||||||
RetryTimerWheel.register(partitionTask.getGroupName(), partitionTask.getUniqueId(), timerTask(partitionTask), delay,
|
RetryTimerWheel.register(partitionTask.getGroupName(), partitionTask.getUniqueId(), timerTask(partitionTask),
|
||||||
|
delay,
|
||||||
TimeUnit.MILLISECONDS);
|
TimeUnit.MILLISECONDS);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -151,7 +158,8 @@ public abstract class AbstractScanGroup extends AbstractActor {
|
|||||||
new LambdaQueryWrapper<RetryTask>()
|
new LambdaQueryWrapper<RetryTask>()
|
||||||
.eq(RetryTask::getRetryStatus, RetryStatusEnum.RUNNING.getStatus())
|
.eq(RetryTask::getRetryStatus, RetryStatusEnum.RUNNING.getStatus())
|
||||||
.eq(RetryTask::getGroupName, groupName).eq(RetryTask::getTaskType, taskType)
|
.eq(RetryTask::getGroupName, groupName).eq(RetryTask::getTaskType, taskType)
|
||||||
.le(RetryTask::getNextTriggerAt, LocalDateTime.now().plusSeconds(10)).gt(RetryTask::getId, lastId)
|
.le(RetryTask::getNextTriggerAt, LocalDateTime.now().plusSeconds(10))
|
||||||
|
.gt(RetryTask::getId, lastId)
|
||||||
.orderByAsc(RetryTask::getId))
|
.orderByAsc(RetryTask::getId))
|
||||||
.getRecords();
|
.getRecords();
|
||||||
|
|
||||||
|
@ -125,16 +125,10 @@ public class JobServiceImpl implements JobService {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean saveJob(JobRequestVO jobRequestVO) {
|
public boolean saveJob(JobRequestVO jobRequestVO) {
|
||||||
WaitStrategy waitStrategy = WaitStrategyEnum.getWaitStrategy(jobRequestVO.getTriggerType());
|
|
||||||
WaitStrategyContext waitStrategyContext = new WaitStrategyContext();
|
|
||||||
waitStrategyContext.setTriggerType(jobRequestVO.getTriggerType());
|
|
||||||
waitStrategyContext.setTriggerInterval(jobRequestVO.getTriggerInterval());
|
|
||||||
waitStrategyContext.setNextTriggerAt(LocalDateTime.now());
|
|
||||||
|
|
||||||
// 判断常驻任务
|
// 判断常驻任务
|
||||||
Job job = updateJobResident(jobRequestVO);
|
Job job = updateJobResident(jobRequestVO);
|
||||||
job.setBucketIndex(HashUtil.bkdrHash(jobRequestVO.getGroupName() + jobRequestVO.getJobName()) % systemProperties.getBucketTotal());
|
job.setBucketIndex(HashUtil.bkdrHash(jobRequestVO.getGroupName() + jobRequestVO.getJobName()) % systemProperties.getBucketTotal());
|
||||||
job.setNextTriggerAt(waitStrategy.computeRetryTime(waitStrategyContext));
|
calculateNextTriggerAt(jobRequestVO, job);
|
||||||
return 1 == jobMapper.insert(job);
|
return 1 == jobMapper.insert(job);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -145,9 +139,19 @@ public class JobServiceImpl implements JobService {
|
|||||||
|
|
||||||
// 判断常驻任务
|
// 判断常驻任务
|
||||||
Job job = updateJobResident(jobRequestVO);
|
Job job = updateJobResident(jobRequestVO);
|
||||||
|
calculateNextTriggerAt(jobRequestVO, job);
|
||||||
return 1 == jobMapper.updateById(job);
|
return 1 == jobMapper.updateById(job);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void calculateNextTriggerAt(final JobRequestVO jobRequestVO, final Job job) {
|
||||||
|
WaitStrategy waitStrategy = WaitStrategyEnum.getWaitStrategy(jobRequestVO.getTriggerType());
|
||||||
|
WaitStrategyContext waitStrategyContext = new WaitStrategyContext();
|
||||||
|
waitStrategyContext.setTriggerType(jobRequestVO.getTriggerType());
|
||||||
|
waitStrategyContext.setTriggerInterval(jobRequestVO.getTriggerInterval());
|
||||||
|
waitStrategyContext.setNextTriggerAt(LocalDateTime.now());
|
||||||
|
job.setNextTriggerAt(waitStrategy.computeRetryTime(waitStrategyContext));
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Job updateJobResident(JobRequestVO jobRequestVO) {
|
public Job updateJobResident(JobRequestVO jobRequestVO) {
|
||||||
Job job = JobConverter.INSTANCE.toJob(jobRequestVO);
|
Job job = JobConverter.INSTANCE.toJob(jobRequestVO);
|
||||||
|
Loading…
Reference in New Issue
Block a user