Skip to content

Commit

Permalink
Switch to platform Independent Task Handler
Browse files Browse the repository at this point in the history
  • Loading branch information
lrmtheboss committed Jan 11, 2025
1 parent 65d19cb commit 28964c5
Show file tree
Hide file tree
Showing 11 changed files with 218 additions and 176 deletions.
38 changes: 19 additions & 19 deletions DriveBackup/src/main/java/ratismal/drivebackup/Scheduler.java
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
package ratismal.drivebackup;

import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.Nullable;
import org.spongepowered.configurate.CommentedConfigurationNode;
import org.spongepowered.configurate.serialize.SerializationException;
import ratismal.drivebackup.configuration.ConfigurationObject;
import ratismal.drivebackup.handler.logging.LoggingInterface;
import ratismal.drivebackup.handler.task.TaskHandler;
import ratismal.drivebackup.handler.task.TaskIdentifier;
import ratismal.drivebackup.handler.task.IndependentTaskHandler;
import ratismal.drivebackup.objects.BackupScheduleEntry;
import ratismal.drivebackup.platforms.DriveBackupInstance;

Expand All @@ -29,6 +27,7 @@
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;

public class Scheduler {
Expand All @@ -41,13 +40,12 @@ public class Scheduler {
/**
* List of the IDs of the scheduled backup tasks
*/
private static final List<TaskIdentifier> backupTasks = new ArrayList<>(2);
private static final List<ScheduledFuture<?>> backupTasks = new ArrayList<>(2);

/**
* ID of the schedule drift correction task
*/
@Nullable
private static TaskIdentifier scheduleDriftTask = null;
private static ScheduledFuture<?> scheduleDriftTask = null;

/**
* List of Dates representing each time a scheduled backup will occur.
Expand All @@ -61,8 +59,8 @@ public Scheduler(DriveBackupInstance instance) {
}

private void cancelAllTasks() {
for (TaskIdentifier taskId : backupTasks) {
instance.getTaskHandler().cancelTask(taskId);
for (ScheduledFuture<?> taskId : backupTasks) {
taskId.cancel(false);
}
}

Expand Down Expand Up @@ -151,7 +149,7 @@ private void loadBackupSchedule() {
*/
public void startBackupThread() {
ConfigurationObject config1 = instance.getConfigHandler().getConfig();
TaskHandler taskHandler = instance.getTaskHandler();
IndependentTaskHandler taskHandler = instance.getTaskHandler();
cancelAllTasks();
if (config1.getValue("scheduled-backups").getBoolean()) {
if (backupSchedule.isEmpty()) {
Expand Down Expand Up @@ -188,9 +186,9 @@ public void startBackupThread() {
}
long delay = ChronoUnit.SECONDS.between(now, startingOccurrence);
long period = ChronoUnit.SECONDS.between(previousBackup, nextBackup);
TaskIdentifier task = taskHandler.scheduleAsyncRepeatingTask(() -> {
ScheduledFuture<?> task = taskHandler.scheduleRepeatingTask(delay, period, TimeUnit.SECONDS, () -> {
new UploadThread(instance);
}, delay, period, TimeUnit.SECONDS);
});
backupTasks.add(task);
backupDatesList.add(startingOccurrence);
}
Expand Down Expand Up @@ -225,24 +223,26 @@ public void startBackupThread() {
.getLang("scheduled-backup-scheduled", placeholders).send();
}
if (scheduleDriftTask != null) {
taskHandler.cancelTask(scheduleDriftTask);
scheduleDriftTask.cancel(false);
}
scheduleDriftTask = taskHandler.scheduleAsyncRepeatingTask(
this::startBackupThread,
scheduleDriftTask = taskHandler.scheduleRepeatingTask(
SCHEDULE_DRIFT_CORRECTION_INTERVAL,
SCHEDULE_DRIFT_CORRECTION_INTERVAL,
TimeUnit.SECONDS);
TimeUnit.SECONDS,
this::startBackupThread);
} else if (config1.getValue("delay").getLong() != -1L) {
if (scheduleDriftTask != null) {
taskHandler.cancelTask(scheduleDriftTask);
scheduleDriftTask.cancel(false);
}
long delayMinutes = config1.getValue("delay").getLong();
instance.getMessageHandler().Builder().toConsole()
.getLang("backups-interval-scheduled", "delay",
String.valueOf(delayMinutes)).send();
backupTasks.add(taskHandler.scheduleAsyncRepeatingTask(
() -> new UploadThread(instance),
delayMinutes, delayMinutes, TimeUnit.MINUTES));
backupTasks.add(taskHandler.scheduleRepeatingTask(
delayMinutes,
delayMinutes,
TimeUnit.MINUTES,
() -> new UploadThread(instance)));
UploadThread.updateNextIntervalBackupTime(instance);
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
package ratismal.drivebackup.handler.task;

import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import ratismal.drivebackup.handler.logging.LoggingHandler;
import ratismal.drivebackup.handler.logging.PrefixedLogger;

import java.util.concurrent.Callable;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;

/**
* A platform independent task handler for scheduling tasks.
*/
public final class IndependentTaskHandler {

private static final long TIMEOUT = 10L;
private static final TimeUnit TIMEOUT_UNIT = TimeUnit.MINUTES;
private static final long KEEP_ALIVE_TIME = 60L;
private static final TimeUnit KEEP_ALIVE_UNIT = TimeUnit.SECONDS;
private static final int MAXIMUM_POOL_SIZE = 100;
private static final int CORE_POOL_SIZE = 0;

private ScheduledExecutorService scheduledExecutor;
private final PrefixedLogger logger;
private ThreadFactory threadFactory;

/**
* Creates a new IndependentTaskHandler instance.
* After constructing, call {@link #setup()} to initialize the handler.
* @param loggingHandler the logging handler to use
*/
@Contract (pure = true)
public IndependentTaskHandler(@NotNull LoggingHandler loggingHandler) {
logger = loggingHandler.getPrefixedLogger("IndependentTaskHandler");
}

/**
* Initializes the task handler.
*/
public void setup() {
threadFactory = new SimpleThreadFactory();
ScheduledThreadPoolExecutor scheduledThreadPoolExecutor = new ScheduledThreadPoolExecutor(CORE_POOL_SIZE, threadFactory);
scheduledThreadPoolExecutor.setMaximumPoolSize(MAXIMUM_POOL_SIZE);
scheduledThreadPoolExecutor.setKeepAliveTime(KEEP_ALIVE_TIME, KEEP_ALIVE_UNIT);
scheduledExecutor = scheduledThreadPoolExecutor;
}

/**
* Shuts down the task handler.
* Waits for tasks to finish for up to 10 minutes.
* If tasks do not finish in time, forces shutdown.
*/
public void shutdown() {
shutdown(TIMEOUT, TIMEOUT_UNIT);
}

/**
* Shuts down the task handler.
* Waits for tasks to finish for up to timeout + unit time.
* If tasks do not finish in time, forces shutdown.
*/
public void shutdown(long timeout, TimeUnit unit){
logger.info("Shutting down IndependentTaskHandler");
logger.info("Shutting down scheduled executor");
scheduledExecutor.shutdown();
logger.info("Waiting for tasks to finish up to " + timeout + " " + unit.toString() + "...");
try {
boolean sch = scheduledExecutor.awaitTermination(timeout, unit);
if (sch) {
logger.info("Scheduled tasks finished");
} else {
logger.error("Scheduled tasks did not finish in time, forcing shutdown");
scheduledExecutor.shutdownNow();
logger.info("Forced scheduled executor shutdown");
}
logger.info("IndependentTaskHandler shutdown complete");
} catch (InterruptedException e) {
logger.error("Was interrupted while waiting for tasks to finish: ", e);
}
}

/**
* Schedules a repeating task.
* The task will run after the delay and then every period.
* <p>
* see {@link ScheduledExecutorService#scheduleAtFixedRate(Runnable, long, long, TimeUnit)}
*
* @param delay the delay before the first run
* @param period the period between runs
* @param unit the time unit of the delay and period
* @param runnable the task to run
* @return a ScheduledFuture representing the task
*/
public @NotNull ScheduledFuture<?> scheduleRepeatingTask(long delay, long period, TimeUnit unit, Runnable runnable) {
return scheduledExecutor.scheduleAtFixedRate(runnable, delay, period, unit);
}

/**
* Schedules a delayed task.
* The task will run after the delay.
* <p>
* see {@link ScheduledExecutorService#schedule(Runnable, long, TimeUnit)}
*
* @param delay the delay before the task runs
* @param unit the time unit of the delay
* @param runnable the task to run
* @return a ScheduledFuture representing the task
*/
public @NotNull ScheduledFuture<?> scheduleLaterTask(long delay, TimeUnit unit, Runnable runnable) {
return scheduledExecutor.schedule(runnable, delay, unit);
}

/**
* Schedules a delayed task.
* The task will run after the delay.
* <p>
* see {@link ScheduledExecutorService#schedule(Callable, long, TimeUnit)}
*
* @param <T> the type of the result
* @param delay the delay
* @param unit the time unit of the delay
* @param callable the task to run
* @return a ScheduledFuture representing the task
*/
public <T> @NotNull ScheduledFuture<T> scheduleLaterTask(long delay, TimeUnit unit, Callable<T> callable) {
return scheduledExecutor.schedule(callable, delay, unit);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package ratismal.drivebackup.handler.task;

import org.jetbrains.annotations.NotNull;

import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicInteger;

public final class SimpleThreadFactory implements ThreadFactory {

private static final AtomicInteger poolNumber = new AtomicInteger(1);
private final ThreadGroup group;
private final AtomicInteger threadNumber = new AtomicInteger(1);
private final String namePrefix;

public SimpleThreadFactory() {
group = Thread.currentThread().getThreadGroup();
namePrefix = "pool-" + poolNumber.getAndIncrement() + "-thread-";
}

public @NotNull Thread newThread(@NotNull Runnable r) {
Thread t = new Thread(group, r,
namePrefix + threadNumber.getAndIncrement(),
0);
if (t.isDaemon()) {
t.setDaemon(false);
}
if (t.getPriority() != Thread.NORM_PRIORITY) {
t.setPriority(Thread.NORM_PRIORITY);
}
return t;
}

}

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public void setup() {
logger.info("Starting update check thread...");
updateTask = new UpdateTask(instance, this);
current = instance.getCurrentVersion();
instance.getTaskHandler().scheduleAsyncRepeatingTask(updateTask, 0L, 6L, TimeUnit.HOURS);
instance.getTaskHandler().scheduleRepeatingTask(0L, 6L, TimeUnit.HOURS, updateTask);
} else {
logger.info("Update check is disabled");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public void run() {
logger.info(message);
Collection<Player> players = instance.getPermissionHandler().getPlayersWithPermission(Permission.RELOAD_CONFIG);
try {
instance.getTaskHandler().callSyncMethod(() -> {
instance.callSyncMethod(() -> {
instance.getPlayerHandler().sendMessage(players, message);
return Boolean.TRUE;
}).get();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,26 @@
import ratismal.drivebackup.handler.messages.MessageHandler;
import ratismal.drivebackup.handler.permission.PermissionHandler;
import ratismal.drivebackup.handler.player.PlayerHandler;
import ratismal.drivebackup.handler.task.TaskHandler;
import ratismal.drivebackup.handler.task.IndependentTaskHandler;
import ratismal.drivebackup.handler.update.UpdateHandler;
import ratismal.drivebackup.objects.Player;
import ratismal.drivebackup.util.Version;

import java.io.File;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;

public interface DriveBackupInstance {

<T> Future<T> callSyncMethod(Callable<T> callable);

void addChatInputPlayer(Player player);

void removeChatInputPlayer(Player player);
boolean isChatInputPlayer(Player player);

IndependentTaskHandler getTaskHandler();
PermissionHandler getPermissionHandler();
File getJarFile();
File getDataDirectory();
Expand All @@ -32,7 +37,6 @@ public interface DriveBackupInstance {
LangConfigHandler getLangConfigHandler();
void disable();
Version getCurrentVersion();
TaskHandler getTaskHandler();
PlayerHandler getPlayerHandler();
UpdateHandler getUpdateHandler();
APIHandler getAPIHandler();
Expand Down
Loading

0 comments on commit 28964c5

Please sign in to comment.