host.anzo.core.startup.ScheduledService Maven / Gradle / Ivy
package host.anzo.core.startup;
import host.anzo.commons.threading.ThreadPool;
import host.anzo.commons.utils.ClassUtils;
import host.anzo.core.service.ForkJoinPoolService;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
/***
* @author ANZO
* @since 8/19/2021
*/
@Slf4j
@StartupComponent(value = "AfterStart", shutdownPriority = EShutdownPriority.MAJOR)
public class ScheduledService implements IShutdownable {
@Getter(lazy=true)
private final static ScheduledService instance = new ScheduledService();
private final List tasks = new ArrayList<>();
private final Map, List> scheduledTasks = new HashMap<>();
private ScheduledService() {
}
@SuppressWarnings("unused")
@StartupRun(before = "AfterStart")
public void scheduleTasks() {
// Run tasks needed to run at server startup
log.info("Running Scheduled methods after server start...");
ForkJoinPoolService.getInstance().forEach("ScheduledService.runAfterServerStart()",
() -> tasks.parallelStream().filter(task -> task.getMethod().getAnnotation(Scheduled.class).runAfterServerStart()).forEach(ScheduledTask::run));
// Schedule all tasks
log.info("Scheduling Scheduled methods tasks...");
for (ScheduledTask task : tasks) {
final Scheduled scheduledAnnotation = task.getMethod().getAnnotation(Scheduled.class);
final TimeUnit timeUnit = scheduledAnnotation.timeUnit();
final long period = scheduledAnnotation.period();
if (TimeUnit.MILLISECONDS.convert(period, timeUnit) <= 0) {
log.error("Delay is zero for scheduled task {}.{}", task.getServiceClass().getSimpleName(), task.getMethod().getName());
continue;
}
final ScheduledFuture> scheduledFuture = ThreadPool.getInstance().scheduleGeneralAtFixedRate(task.getServiceClass().getSimpleName() + "." + task.getMethod().getName(), task, period, period, timeUnit);
task.setScheduledFuture(scheduledFuture);
scheduledTasks.computeIfAbsent(task.getServiceClass(), k -> new ArrayList<>()).add(task);
}
}
protected void addScheduledMethod(@NotNull Class> serviceClass, @NotNull Method method) {
if (method.isAnnotationPresent(Scheduled.class)) {
tasks.add(new ScheduledTask(serviceClass, method));
}
}
@Override
public void onShutdown() {
for (List scheduledTasks : scheduledTasks.values()) {
for (ScheduledTask scheduledTask : scheduledTasks) {
try {
scheduledTask.getScheduledFuture().cancel(true);
}
catch (Exception ignored) {
}
}
}
}
private static @Getter class ScheduledTask implements Runnable {
private final Class> serviceClass;
private final Method method;
private @Setter ScheduledFuture> scheduledFuture;
ScheduledTask(@NotNull Class> serviceClass, @NotNull Method method) {
this.serviceClass = serviceClass;
this.method = method;
}
@Override
public void run() {
try {
ClassUtils.singletonInstanceMethod(serviceClass, method);
}
catch (Exception e) {
log.error("Error while calling scheduled task at {}.{}", serviceClass.getSimpleName(), method.getName(), e);
}
}
}
}