From 688c0ae4c274cd54309b330b45116588f6e24e98 Mon Sep 17 00:00:00 2001 From: jvyden Date: Fri, 5 Aug 2022 19:27:37 -0400 Subject: [PATCH] Add system for repeating tasks on a regular basis --- .../Maintenance/IRepeatingTask.cs | 13 ++++ .../Maintenance/MaintenanceHelper.cs | 4 ++ .../RepeatingTasks/CleanupRoomsTask.cs | 13 ++++ .../RepeatingTasks/RemoveExpiredTokensTask.cs | 13 ++++ .../Administration/RepeatingTaskHandler.cs | 62 +++++++++++++++++++ ProjectLighthouse/Logging/LogArea.cs | 1 + ProjectLighthouse/Match/Rooms/RoomHelper.cs | 16 ----- ProjectLighthouse/StartupTasks.cs | 11 ++-- 8 files changed, 110 insertions(+), 23 deletions(-) create mode 100644 ProjectLighthouse/Administration/Maintenance/IRepeatingTask.cs create mode 100644 ProjectLighthouse/Administration/Maintenance/RepeatingTasks/CleanupRoomsTask.cs create mode 100644 ProjectLighthouse/Administration/Maintenance/RepeatingTasks/RemoveExpiredTokensTask.cs create mode 100644 ProjectLighthouse/Administration/RepeatingTaskHandler.cs diff --git a/ProjectLighthouse/Administration/Maintenance/IRepeatingTask.cs b/ProjectLighthouse/Administration/Maintenance/IRepeatingTask.cs new file mode 100644 index 00000000..021c3c44 --- /dev/null +++ b/ProjectLighthouse/Administration/Maintenance/IRepeatingTask.cs @@ -0,0 +1,13 @@ +using System; +using System.Threading.Tasks; + +namespace LBPUnion.ProjectLighthouse.Administration.Maintenance; + +public interface IRepeatingTask +{ + public string Name { get; } + public TimeSpan RepeatInterval { get; } + public DateTime LastRan { get; set; } + + public Task Run(Database database); +} \ No newline at end of file diff --git a/ProjectLighthouse/Administration/Maintenance/MaintenanceHelper.cs b/ProjectLighthouse/Administration/Maintenance/MaintenanceHelper.cs index 7d7490d8..7d92209b 100644 --- a/ProjectLighthouse/Administration/Maintenance/MaintenanceHelper.cs +++ b/ProjectLighthouse/Administration/Maintenance/MaintenanceHelper.cs @@ -2,8 +2,10 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Reflection; +using System.Threading; using System.Threading.Tasks; using LBPUnion.ProjectLighthouse.Extensions; using LBPUnion.ProjectLighthouse.Logging; @@ -18,11 +20,13 @@ public static class MaintenanceHelper Commands = getListOfInterfaceObjects(); MaintenanceJobs = getListOfInterfaceObjects(); MigrationTasks = getListOfInterfaceObjects(); + RepeatingTasks = getListOfInterfaceObjects(); } public static List Commands { get; } public static List MaintenanceJobs { get; } public static List MigrationTasks { get; } + public static List RepeatingTasks { get; } public static async Task> RunCommand(string[] args) { diff --git a/ProjectLighthouse/Administration/Maintenance/RepeatingTasks/CleanupRoomsTask.cs b/ProjectLighthouse/Administration/Maintenance/RepeatingTasks/CleanupRoomsTask.cs new file mode 100644 index 00000000..463350b1 --- /dev/null +++ b/ProjectLighthouse/Administration/Maintenance/RepeatingTasks/CleanupRoomsTask.cs @@ -0,0 +1,13 @@ +using System; +using System.Threading.Tasks; +using LBPUnion.ProjectLighthouse.Match.Rooms; + +namespace LBPUnion.ProjectLighthouse.Administration.Maintenance.RepeatingTasks; + +public class CleanupRoomsTask : IRepeatingTask +{ + public string Name => "Cleanup Rooms"; + public TimeSpan RepeatInterval => TimeSpan.FromSeconds(10); + public DateTime LastRan { get; set; } + public async Task Run(Database database) => RoomHelper.CleanupRooms(); +} \ No newline at end of file diff --git a/ProjectLighthouse/Administration/Maintenance/RepeatingTasks/RemoveExpiredTokensTask.cs b/ProjectLighthouse/Administration/Maintenance/RepeatingTasks/RemoveExpiredTokensTask.cs new file mode 100644 index 00000000..897196bf --- /dev/null +++ b/ProjectLighthouse/Administration/Maintenance/RepeatingTasks/RemoveExpiredTokensTask.cs @@ -0,0 +1,13 @@ +using System; +using System.Threading.Tasks; + +namespace LBPUnion.ProjectLighthouse.Administration.Maintenance.RepeatingTasks; + +public class RemoveExpiredTokensTask : IRepeatingTask +{ + public string Name => "Remove Expired Tokens"; + public TimeSpan RepeatInterval => TimeSpan.FromHours(1); + public DateTime LastRan { get; set; } + + public Task Run(Database database) => database.RemoveExpiredTokens(); +} \ No newline at end of file diff --git a/ProjectLighthouse/Administration/RepeatingTaskHandler.cs b/ProjectLighthouse/Administration/RepeatingTaskHandler.cs new file mode 100644 index 00000000..9d194310 --- /dev/null +++ b/ProjectLighthouse/Administration/RepeatingTaskHandler.cs @@ -0,0 +1,62 @@ +#nullable enable +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Threading; +using System.Threading.Tasks; +using LBPUnion.ProjectLighthouse.Administration.Maintenance; +using LBPUnion.ProjectLighthouse.Logging; + +namespace LBPUnion.ProjectLighthouse.Administration; + +public static class RepeatingTaskHandler +{ + private static bool initialized = false; + + public static void Initialize() + { + if (initialized) throw new InvalidOperationException("RepeatingTaskHandler was initialized twice"); + + initialized = true; + Task.Factory.StartNew(taskLoop); + } + + [SuppressMessage("ReSharper", "FunctionNeverReturns")] + private static async Task taskLoop() + { + Queue taskQueue = new(); + foreach (IRepeatingTask task in MaintenanceHelper.RepeatingTasks) taskQueue.Enqueue(task); + + Database database = new(); + + while (true) + { + try + { + if (!taskQueue.TryDequeue(out IRepeatingTask? task)) + { + Thread.Sleep(100); + continue; + } + + Debug.Assert(task != null); + + if ((task.LastRan + task.RepeatInterval) <= DateTime.Now) + { + await task.Run(database); + task.LastRan = DateTime.Now; + + Logger.Debug($"Ran task \"{task.Name}\"", LogArea.Maintenace); + } + + taskQueue.Enqueue(task); + Thread.Sleep(500); // Doesn't need to be that precise. + } + catch + { + // ignored + } + } + } +} \ No newline at end of file diff --git a/ProjectLighthouse/Logging/LogArea.cs b/ProjectLighthouse/Logging/LogArea.cs index 3a8a6ad6..0612af9f 100644 --- a/ProjectLighthouse/Logging/LogArea.cs +++ b/ProjectLighthouse/Logging/LogArea.cs @@ -22,4 +22,5 @@ public enum LogArea Command, Admin, Publish, + Maintenace, } \ No newline at end of file diff --git a/ProjectLighthouse/Match/Rooms/RoomHelper.cs b/ProjectLighthouse/Match/Rooms/RoomHelper.cs index 8726c216..b68af7f9 100644 --- a/ProjectLighthouse/Match/Rooms/RoomHelper.cs +++ b/ProjectLighthouse/Match/Rooms/RoomHelper.cs @@ -21,22 +21,6 @@ public class RoomHelper public static readonly object RoomLock = new(); public static StorableList Rooms => RoomStore.GetRooms(); - public static void StartCleanupThread() - { - // ReSharper disable once FunctionNeverReturns - Task.Factory.StartNew - ( - async () => - { - while (true) - { - CleanupRooms(); - await Task.Delay(10000); - } - } - ); - } - private static int roomIdIncrement; internal static int RoomIdIncrement => roomIdIncrement++; diff --git a/ProjectLighthouse/StartupTasks.cs b/ProjectLighthouse/StartupTasks.cs index 95497e90..0025a895 100644 --- a/ProjectLighthouse/StartupTasks.cs +++ b/ProjectLighthouse/StartupTasks.cs @@ -89,14 +89,11 @@ public static class StartupTasks Logger.Info("Initializing Redis...", LogArea.Startup); RedisDatabase.Initialize().Wait(); + + Logger.Info("Initializing repeating tasks...", LogArea.Startup); + RepeatingTaskHandler.Initialize(); - if (serverType == ServerType.GameServer) - { - Logger.Info("Starting room cleanup thread...", LogArea.Startup); - RoomHelper.StartCleanupThread(); - } - - // Create admin user if no users exist + // Create admin user if no users exist if (serverType == ServerType.Website && database.Users.CountAsync().Result == 0) { const string passwordClear = "lighthouse";