項目中使用了寫出Apollo進行配置管理,需要實現動態配置Job的執行間隔。
使用動態修改cron表達式的方式可以實現,但是cron表達式不支持毫秒,所以採用以下方式進行配置。
每次配置改動時,將舊的定時任務停掉,重新啓動一個定時任務。
/**
* shang
* 2020-02-11 15:41
*/
@Slf4j
@Component
public class OrderJob {
// 訂單寬表定時同步間隔,單位ms
@Value("${order.schedule.interval:1000}")
private Long orderScheduleInterVal;
private static final String lock = "lock";
private final Set<String> orderIdSet = Sets.newHashSet();
@Resource
private OrderManager orderManager;
@Resource
private ThreadPoolTaskScheduler threadPoolTaskScheduler;
@ApolloConfig
private Config config;
private ScheduledFuture<?> future;
@ApolloConfigChangeListener
private void configChangeListener(ConfigChangeEvent changeEvent) {
Set<String> keyNames = config.getPropertyNames();
for (String key : keyNames) {
if (StringUtils.equals(key, "order.schedule.interval")) {
String interVal = config.getProperty(key, "1000");
if (future != null) {
future.cancel(true);
log.info("cancel order task");
}
PeriodicTrigger periodicTrigger = new PeriodicTrigger(Long.valueOf(interVal), TimeUnit.MILLISECONDS);
periodicTrigger.setFixedRate(true);
periodicTrigger.setInitialDelay(1000);
future = threadPoolTaskScheduler.schedule(this::readOrderIdSet, periodicTrigger);
log.info("start order task");
}
log.info("{}:{}", key, config.getProperty(key, null));
}
}
/**
* 寫入緩衝set
*
* @param orderIds
*/
public void writeOrderIdSet(Set<String> orderIds) {
if (CollectionUtils.isEmpty(orderIds)) {
return;
}
synchronized (lock) {
orderIdSet.addAll(orderIds);
}
}
/**
* 定時任務從緩衝set裏取
*/
// 這樣配置無法動態修改執行間隔
// @Scheduled(fixedRate = 2000)
public void readOrderIdSet() {
if (CollectionUtils.isEmpty(orderIdSet)) {
log.info("緩衝set爲空,定時任務不執行");
return;
}
synchronized (lock) {
log.info("發送訂單寬表消息:{}條", CollectionUtils.size(orderIdSet));
// 緩衝區的orderId發kafka消息
orderManager.sendMessage(orderIdSet);
// 清空緩衝區
orderIdSet.clear();
}
}
@PostConstruct
public void postConstruct() {
PeriodicTrigger periodicTrigger = new PeriodicTrigger(orderScheduleInterVal, TimeUnit.MILLISECONDS);
periodicTrigger.setFixedRate(true);
periodicTrigger.setInitialDelay(1000);
future = threadPoolTaskScheduler.schedule(this::readOrderIdSet, periodicTrigger);
}
}