增加定时任务功能
This commit is contained in:
@@ -29,6 +29,7 @@ module org.redkale {
|
|||||||
exports org.redkale.net.http;
|
exports org.redkale.net.http;
|
||||||
exports org.redkale.net.sncp;
|
exports org.redkale.net.sncp;
|
||||||
exports org.redkale.persistence;
|
exports org.redkale.persistence;
|
||||||
|
exports org.redkale.scheduling;
|
||||||
exports org.redkale.service;
|
exports org.redkale.service;
|
||||||
exports org.redkale.source;
|
exports org.redkale.source;
|
||||||
exports org.redkale.util;
|
exports org.redkale.util;
|
||||||
|
|||||||
@@ -20,16 +20,57 @@ import java.util.concurrent.TimeUnit;
|
|||||||
@Retention(RetentionPolicy.RUNTIME)
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
public @interface Scheduled {
|
public @interface Scheduled {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 名称
|
||||||
|
*
|
||||||
|
* @return 名称
|
||||||
|
*/
|
||||||
|
String name() default "";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* cron表达式
|
||||||
|
*
|
||||||
|
* @return cron表达式
|
||||||
|
*/
|
||||||
String cron() default "";
|
String cron() default "";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 时区
|
||||||
|
*
|
||||||
|
* @return 时区
|
||||||
|
*/
|
||||||
String zone() default "";
|
String zone() default "";
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @return deplay时间
|
||||||
|
*/
|
||||||
String fixedDelay() default "-1";
|
String fixedDelay() default "-1";
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @return 周期时间
|
||||||
|
*/
|
||||||
String fixedRate() default "-1";
|
String fixedRate() default "-1";
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @return 起始deplay时间
|
||||||
|
*/
|
||||||
String initialDelay() default "-1";
|
String initialDelay() default "-1";
|
||||||
|
|
||||||
TimeUnit timeUnit() default TimeUnit.MILLISECONDS;
|
/**
|
||||||
|
* 时间单元
|
||||||
|
*
|
||||||
|
* @return 时间单元
|
||||||
|
*/
|
||||||
|
TimeUnit timeUnit() default TimeUnit.SECONDS;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 备注
|
||||||
|
*
|
||||||
|
* @return 备注
|
||||||
|
*/
|
||||||
|
String comment() default "";
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ import org.redkale.mq.*;
|
|||||||
import org.redkale.net.*;
|
import org.redkale.net.*;
|
||||||
import org.redkale.net.http.*;
|
import org.redkale.net.http.*;
|
||||||
import org.redkale.net.sncp.*;
|
import org.redkale.net.sncp.*;
|
||||||
|
import org.redkale.scheduling.ScheduledFactory;
|
||||||
import org.redkale.service.Service;
|
import org.redkale.service.Service;
|
||||||
import org.redkale.source.*;
|
import org.redkale.source.*;
|
||||||
import org.redkale.util.*;
|
import org.redkale.util.*;
|
||||||
@@ -205,6 +206,9 @@ public final class Application {
|
|||||||
//全局根ResourceFactory
|
//全局根ResourceFactory
|
||||||
final ResourceFactory resourceFactory = ResourceFactory.create();
|
final ResourceFactory resourceFactory = ResourceFactory.create();
|
||||||
|
|
||||||
|
//全局ScheduledFactory
|
||||||
|
private final ScheduledFactory scheduledFactory;
|
||||||
|
|
||||||
//服务配置项
|
//服务配置项
|
||||||
final AnyValue config;
|
final AnyValue config;
|
||||||
|
|
||||||
@@ -627,6 +631,10 @@ public final class Application {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{ //设置ScheduledFactory
|
||||||
|
this.scheduledFactory = ScheduledFactory.create(this::getPropertyValue).disable(isCompileMode());
|
||||||
|
}
|
||||||
|
|
||||||
{ //加载原生sql解析器
|
{ //加载原生sql解析器
|
||||||
Iterator<DataNativeSqlParserProvider> it = ServiceLoader.load(DataNativeSqlParserProvider.class, classLoader).iterator();
|
Iterator<DataNativeSqlParserProvider> it = ServiceLoader.load(DataNativeSqlParserProvider.class, classLoader).iterator();
|
||||||
RedkaleClassLoader.putServiceLoader(DataNativeSqlParserProvider.class);
|
RedkaleClassLoader.putServiceLoader(DataNativeSqlParserProvider.class);
|
||||||
@@ -2159,6 +2167,14 @@ public final class Application {
|
|||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void schedule(Object service) {
|
||||||
|
this.scheduledFactory.schedule(service);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void unschedule(Object service) {
|
||||||
|
this.scheduledFactory.unschedule(service);
|
||||||
|
}
|
||||||
|
|
||||||
void updateEnvironmentProperties(String namespace, List<ResourceEvent> events) {
|
void updateEnvironmentProperties(String namespace, List<ResourceEvent> events) {
|
||||||
if (events == null || events.isEmpty()) {
|
if (events == null || events.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
@@ -2622,6 +2638,8 @@ public final class Application {
|
|||||||
if (this.workExecutor != null) {
|
if (this.workExecutor != null) {
|
||||||
this.workExecutor.shutdownNow();
|
this.workExecutor.shutdownNow();
|
||||||
}
|
}
|
||||||
|
this.scheduledFactory.destroy();
|
||||||
|
|
||||||
long intms = System.currentTimeMillis() - f;
|
long intms = System.currentTimeMillis() - f;
|
||||||
String ms = String.valueOf(intms);
|
String ms = String.valueOf(intms);
|
||||||
int repeat = ms.length() > 7 ? 0 : (7 - ms.length()) / 2;
|
int repeat = ms.length() > 7 ? 0 : (7 - ms.length()) / 2;
|
||||||
|
|||||||
@@ -612,6 +612,7 @@ public abstract class NodeServer {
|
|||||||
localServices.stream().forEach(y -> {
|
localServices.stream().forEach(y -> {
|
||||||
long s = System.currentTimeMillis();
|
long s = System.currentTimeMillis();
|
||||||
y.init(Sncp.getResourceConf(y));
|
y.init(Sncp.getResourceConf(y));
|
||||||
|
application.schedule(y);
|
||||||
long e = System.currentTimeMillis() - s;
|
long e = System.currentTimeMillis() - s;
|
||||||
if (slist != null) {
|
if (slist != null) {
|
||||||
String serstr = Sncp.toSimpleString(y, maxNameLength, maxTypeLength);
|
String serstr = Sncp.toSimpleString(y, maxNameLength, maxTypeLength);
|
||||||
@@ -876,6 +877,7 @@ public abstract class NodeServer {
|
|||||||
if (finest) {
|
if (finest) {
|
||||||
logger.finest(Sncp.getResourceType(y) + " is destroying");
|
logger.finest(Sncp.getResourceType(y) + " is destroying");
|
||||||
}
|
}
|
||||||
|
application.unschedule(y);
|
||||||
y.destroy(Sncp.getResourceConf(y));
|
y.destroy(Sncp.getResourceConf(y));
|
||||||
if (finest) {
|
if (finest) {
|
||||||
logger.finest(Sncp.getResourceType(y) + " was destroyed");
|
logger.finest(Sncp.getResourceType(y) + " was destroyed");
|
||||||
|
|||||||
@@ -135,9 +135,10 @@ public abstract class Sncp {
|
|||||||
}
|
}
|
||||||
if (method.getAnnotation(Scheduled.class) != null) {
|
if (method.getAnnotation(Scheduled.class) != null) {
|
||||||
if (Modifier.isStatic(method.getModifiers())
|
if (Modifier.isStatic(method.getModifiers())
|
||||||
|| !Modifier.isProtected(method.getModifiers()) || method.getParameterCount() > 0) {
|
|| method.getParameterCount() > 0) {
|
||||||
throw new SncpException(Scheduled.class.getSimpleName() + " must be on protected and non-parameter method, but on " + method);
|
throw new SncpException(Scheduled.class.getSimpleName() + " must be on protected and non-parameter method, but on " + method);
|
||||||
}
|
}
|
||||||
|
RedkaleClassLoader.putReflectionMethod(serviceTypeOrImplClass.getName(), method);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (Modifier.isStatic(method.getModifiers())) {
|
if (Modifier.isStatic(method.getModifiers())) {
|
||||||
|
|||||||
@@ -1,12 +1,19 @@
|
|||||||
/*
|
/*
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
package org.redkale.util;
|
package org.redkale.scheduling;
|
||||||
|
|
||||||
import java.time.DateTimeException;
|
import java.time.DateTimeException;
|
||||||
import java.time.temporal.*;
|
import java.time.temporal.ChronoField;
|
||||||
import java.util.*;
|
import java.time.temporal.ChronoUnit;
|
||||||
|
import java.time.temporal.Temporal;
|
||||||
|
import java.time.temporal.ValueRange;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
import org.redkale.annotation.Nullable;
|
import org.redkale.annotation.Nullable;
|
||||||
|
import org.redkale.util.RedkaleException;
|
||||||
|
import org.redkale.util.Utility;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* cron定时表达式解析器 <br> 代码复制于org.springframework.scheduling.support.CronExpression
|
* cron定时表达式解析器 <br> 代码复制于org.springframework.scheduling.support.CronExpression
|
||||||
@@ -28,7 +35,8 @@ public class CronExpression {
|
|||||||
"@weekly", "0 0 0 * * 0",
|
"@weekly", "0 0 0 * * 0",
|
||||||
"@daily", "0 0 0 * * *",
|
"@daily", "0 0 0 * * *",
|
||||||
"@midnight", "0 0 0 * * *",
|
"@midnight", "0 0 0 * * *",
|
||||||
"@hourly", "0 0 * * * *"
|
"@hourly", "0 0 * * * *",
|
||||||
|
"@minutely", "0 0/1 * * * *"
|
||||||
};
|
};
|
||||||
|
|
||||||
private final CronField[] fields;
|
private final CronField[] fields;
|
||||||
306
src/main/java/org/redkale/scheduling/ScheduledFactory.java
Normal file
306
src/main/java/org/redkale/scheduling/ScheduledFactory.java
Normal file
@@ -0,0 +1,306 @@
|
|||||||
|
/*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
package org.redkale.scheduling;
|
||||||
|
|
||||||
|
import java.lang.ref.WeakReference;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.lang.reflect.Modifier;
|
||||||
|
import java.time.Duration;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.time.ZoneId;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.concurrent.ScheduledFuture;
|
||||||
|
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
|
import java.util.function.UnaryOperator;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
import org.redkale.annotation.Nullable;
|
||||||
|
import org.redkale.annotation.Scheduled;
|
||||||
|
import org.redkale.util.RedkaleClassLoader;
|
||||||
|
import org.redkale.util.RedkaleException;
|
||||||
|
import org.redkale.util.Utility;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 定时任务工厂
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* 详情见: https://redkale.org
|
||||||
|
*
|
||||||
|
* @author zhangjx
|
||||||
|
* @since 2.8.0
|
||||||
|
*/
|
||||||
|
public class ScheduledFactory {
|
||||||
|
|
||||||
|
protected final Logger logger = Logger.getLogger(this.getClass().getSimpleName());
|
||||||
|
|
||||||
|
private final ConcurrentHashMap<WeakReference, List<ScheduledTask>> refTaskMap = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
private final ReentrantLock lock = new ReentrantLock();
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private final UnaryOperator<String> propertyFunc;
|
||||||
|
|
||||||
|
private final ScheduledThreadPoolExecutor scheduler;
|
||||||
|
|
||||||
|
private boolean disable;
|
||||||
|
|
||||||
|
protected ScheduledFactory(UnaryOperator<String> propertyFunc) {
|
||||||
|
this.propertyFunc = propertyFunc;
|
||||||
|
this.scheduler = new ScheduledThreadPoolExecutor(Utility.cpus(), Utility.newThreadFactory("Scheduled-Task-Thread-%s"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ScheduledFactory create(UnaryOperator<String> propertyFunc) {
|
||||||
|
return new ScheduledFactory(propertyFunc);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ScheduledFactory disable(boolean val) {
|
||||||
|
this.disable = val;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void unschedule(Object service) {
|
||||||
|
lock.lock();
|
||||||
|
try {
|
||||||
|
Map.Entry<WeakReference, List<ScheduledTask>> entry = null;
|
||||||
|
for (Map.Entry<WeakReference, List<ScheduledTask>> item : refTaskMap.entrySet()) {
|
||||||
|
if (item.getKey().get() == service) {
|
||||||
|
entry = item;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (entry == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
refTaskMap.remove(entry.getKey());
|
||||||
|
for (ScheduledTask task : entry.getValue()) {
|
||||||
|
task.cancel();
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
lock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void schedule(Object service) {
|
||||||
|
lock.lock();
|
||||||
|
try {
|
||||||
|
for (WeakReference item : refTaskMap.keySet()) {
|
||||||
|
if (item.get() == service) {
|
||||||
|
logger.log(Level.WARNING, service + " repeat schedule");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Map<String, ScheduledTask> tasks = new LinkedHashMap<>();
|
||||||
|
Class clazz = service.getClass();
|
||||||
|
WeakReference ref = new WeakReference(service);
|
||||||
|
do {
|
||||||
|
for (final Method method : clazz.getDeclaredMethods()) {
|
||||||
|
if (method.getAnnotation(Scheduled.class) == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (tasks.containsKey(method.getName())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (method.getParameterCount() > 0) {
|
||||||
|
throw new RedkaleException("@" + Scheduled.class.getSimpleName() + " must be on non-parameter method, but on " + method);
|
||||||
|
}
|
||||||
|
ScheduledTask task = schedule(ref, method);
|
||||||
|
if (task == null) {
|
||||||
|
continue; //时间都没配置
|
||||||
|
}
|
||||||
|
tasks.put(method.getName(), task);
|
||||||
|
RedkaleClassLoader.putReflectionMethod(clazz.getName(), method);
|
||||||
|
}
|
||||||
|
} while ((clazz = clazz.getSuperclass()) != Object.class);
|
||||||
|
//开始执行定时任务
|
||||||
|
if (!disable && !tasks.isEmpty()) {
|
||||||
|
tasks.forEach((name, task) -> task.start());
|
||||||
|
refTaskMap.put(ref, new ArrayList<>(tasks.values()));
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
lock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected ScheduledTask schedule(WeakReference ref, Method method) {
|
||||||
|
Scheduled ann = method.getAnnotation(Scheduled.class);
|
||||||
|
String name = getProperty(ann.name());
|
||||||
|
String cron = getProperty(ann.cron());
|
||||||
|
String fixedDelay = getProperty(ann.fixedDelay());
|
||||||
|
String fixedRate = getProperty(ann.fixedRate());
|
||||||
|
String initialDelay = getProperty(ann.initialDelay());
|
||||||
|
String zone = getProperty(ann.zone());
|
||||||
|
TimeUnit timeUnit = ann.timeUnit();
|
||||||
|
if ((cron.isEmpty() || "-".equals(cron)) && "-1".equals(fixedRate) && "-1".endsWith(fixedDelay)) {
|
||||||
|
return null; //时间都没配置
|
||||||
|
}
|
||||||
|
ZoneId zoneId = Utility.isEmpty(zone) ? null : ZoneId.of(zone);
|
||||||
|
if (!cron.isEmpty() && !"-".equals(cron)) {
|
||||||
|
CronExpression cronExpr = CronExpression.parse(cron);
|
||||||
|
return new CronTask(ref, name, method, cronExpr, zoneId);
|
||||||
|
} else {
|
||||||
|
long fixedDelayLong = Long.parseLong(fixedDelay);
|
||||||
|
long fixedRateLong = Long.parseLong(fixedRate);
|
||||||
|
long initialDelayLong = Long.parseLong(initialDelay);
|
||||||
|
return new FixedTask(ref, name, method, fixedDelayLong, fixedRateLong, initialDelayLong, timeUnit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Runnable createRunnable(final WeakReference ref, Method method) {
|
||||||
|
if (!Modifier.isPublic(method.getModifiers())) {
|
||||||
|
method.setAccessible(true);
|
||||||
|
}
|
||||||
|
return () -> {
|
||||||
|
try {
|
||||||
|
Object obj = ref.get();
|
||||||
|
if (obj != null) {
|
||||||
|
if (logger.isLoggable(Level.FINEST)) {
|
||||||
|
logger.log(Level.FINEST, "schedule task " + method.getDeclaringClass().getSimpleName() + "." + method.getName());
|
||||||
|
}
|
||||||
|
method.invoke(obj);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.log(Level.SEVERE, "schedule task error", e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String getProperty(String value) {
|
||||||
|
if (propertyFunc == null || value.indexOf('}') < 0) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
return propertyFunc.apply(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void destroy() {
|
||||||
|
if (scheduler != null) {
|
||||||
|
scheduler.shutdown();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract class ScheduledTask implements Runnable {
|
||||||
|
|
||||||
|
protected final WeakReference ref;
|
||||||
|
|
||||||
|
protected final String name;
|
||||||
|
|
||||||
|
protected final Method method;
|
||||||
|
|
||||||
|
protected ScheduledFuture future;
|
||||||
|
|
||||||
|
protected ScheduledTask(WeakReference ref, String name, Method method) {
|
||||||
|
Objects.requireNonNull(ref);
|
||||||
|
Objects.requireNonNull(name);
|
||||||
|
Objects.requireNonNull(method);
|
||||||
|
this.ref = ref;
|
||||||
|
this.name = name;
|
||||||
|
this.method = method;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract void start();
|
||||||
|
|
||||||
|
public void cancel() {
|
||||||
|
if (future != null) {
|
||||||
|
future.cancel(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Method method() {
|
||||||
|
return method;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String name() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected class FixedTask extends ScheduledTask {
|
||||||
|
|
||||||
|
private final Runnable delegate;
|
||||||
|
|
||||||
|
private final long fixedDelay;
|
||||||
|
|
||||||
|
private final long fixedRate;
|
||||||
|
|
||||||
|
private final long initialDelay;
|
||||||
|
|
||||||
|
private final TimeUnit timeUnit;
|
||||||
|
|
||||||
|
public FixedTask(final WeakReference ref, String name, Method method, long fixedDelay, long fixedRate, long initialDelay, TimeUnit timeUnit) {
|
||||||
|
super(ref, name, method);
|
||||||
|
this.delegate = createRunnable(ref, method);
|
||||||
|
this.fixedDelay = fixedDelay;
|
||||||
|
this.fixedRate = fixedRate;
|
||||||
|
this.initialDelay = initialDelay;
|
||||||
|
this.timeUnit = timeUnit;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
delegate.run();
|
||||||
|
} catch (Throwable t) {
|
||||||
|
logger.log(Level.SEVERE, "schedule task error", t);
|
||||||
|
}
|
||||||
|
if (ref.get() == null) {
|
||||||
|
cancel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void start() {
|
||||||
|
if (fixedRate > 0) {
|
||||||
|
this.future = scheduler.scheduleAtFixedRate(this, initialDelay > 0 ? initialDelay : 0, fixedRate, timeUnit);
|
||||||
|
} else if (fixedDelay > 0) {
|
||||||
|
this.future = scheduler.scheduleWithFixedDelay(this, initialDelay, fixedDelay, timeUnit);
|
||||||
|
} else if (initialDelay > 0) {
|
||||||
|
this.future = scheduler.schedule(this, initialDelay, timeUnit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected class CronTask extends ScheduledTask {
|
||||||
|
|
||||||
|
private final Runnable delegate;
|
||||||
|
|
||||||
|
private final CronExpression cron;
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private final ZoneId zoneId;
|
||||||
|
|
||||||
|
public CronTask(WeakReference ref, String name, Method method, CronExpression cron, ZoneId zoneId) {
|
||||||
|
super(ref, name, method);
|
||||||
|
this.delegate = createRunnable(ref, method);
|
||||||
|
this.cron = cron;
|
||||||
|
this.zoneId = zoneId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
delegate.run();
|
||||||
|
} catch (Throwable t) {
|
||||||
|
logger.log(Level.SEVERE, "schedule task error", t);
|
||||||
|
}
|
||||||
|
start();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void start() {
|
||||||
|
if (ref.get() == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
LocalDateTime now = zoneId == null ? LocalDateTime.now() : LocalDateTime.now(zoneId);
|
||||||
|
LocalDateTime next = cron.next(now);
|
||||||
|
Duration delay = Duration.between(now, next);
|
||||||
|
this.future = scheduler.schedule(this, delay.toNanos(), TimeUnit.NANOSECONDS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -59,6 +59,7 @@ public class RedkaleClassLoader extends URLClassLoader {
|
|||||||
"org.redkale.net.http",
|
"org.redkale.net.http",
|
||||||
"org.redkale.net.sncp",
|
"org.redkale.net.sncp",
|
||||||
"org.redkale.persistence",
|
"org.redkale.persistence",
|
||||||
|
"org.redkale.scheduling",
|
||||||
"org.redkale.service",
|
"org.redkale.service",
|
||||||
"org.redkale.source",
|
"org.redkale.source",
|
||||||
"org.redkale.util",
|
"org.redkale.util",
|
||||||
|
|||||||
Reference in New Issue
Block a user