refactor!: Use Func<Task> for scheduled tasks
This commit is contained in:
parent
647d7c4a1c
commit
bc8eb1ac0d
5 changed files with 98 additions and 66 deletions
35
Entities/ScheduledTask.cs
Normal file
35
Entities/ScheduledTask.cs
Normal file
|
|
@ -0,0 +1,35 @@
|
||||||
|
namespace Xorog.UniversalExtensions.Entities;
|
||||||
|
|
||||||
|
public class ScheduledTask
|
||||||
|
{
|
||||||
|
internal ScheduledTask()
|
||||||
|
{
|
||||||
|
this.Uid = Guid.NewGuid().ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The unique identifier of this task.
|
||||||
|
/// </summary>
|
||||||
|
public string Uid { get; internal set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The custom data asscociated with this task.
|
||||||
|
/// </summary>
|
||||||
|
public object? CustomData { get; internal set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The time this task will run.
|
||||||
|
/// </summary>
|
||||||
|
public DateTime? RunTime { get; internal set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The <see cref="CancellationTokenSource"/> to prematurely dequeue this task.
|
||||||
|
/// </summary>
|
||||||
|
internal CancellationTokenSource? TokenSource { get; set; } = new();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Delete this task.
|
||||||
|
/// </summary>
|
||||||
|
public void Delete() =>
|
||||||
|
ScheduledTaskExtensions.DeleteScheduledTask(Uid);
|
||||||
|
}
|
||||||
22
EventArgs/ScheduledTaskStartedEventArgs.cs
Normal file
22
EventArgs/ScheduledTaskStartedEventArgs.cs
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
using Xorog.UniversalExtensions.Entities;
|
||||||
|
|
||||||
|
namespace Xorog.UniversalExtensions.EventArgs;
|
||||||
|
|
||||||
|
public class ScheduledTaskStartedEventArgs : System.EventArgs
|
||||||
|
{
|
||||||
|
internal ScheduledTaskStartedEventArgs(ScheduledTask details, Task task)
|
||||||
|
{
|
||||||
|
this.Details = details;
|
||||||
|
this.Task = task;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The details of this scheduled task.
|
||||||
|
/// </summary>
|
||||||
|
public ScheduledTask Details { get; internal set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The task that was executed.
|
||||||
|
/// </summary>
|
||||||
|
public Task Task { get; internal set; }
|
||||||
|
}
|
||||||
|
|
@ -1,52 +1,61 @@
|
||||||
namespace Xorog.UniversalExtensions;
|
using Xorog.UniversalExtensions.Entities;
|
||||||
|
using Xorog.UniversalExtensions.EventArgs;
|
||||||
|
|
||||||
|
namespace Xorog.UniversalExtensions;
|
||||||
public static class ScheduledTaskExtensions
|
public static class ScheduledTaskExtensions
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Fired when a log message has been sent.
|
||||||
|
/// </summary>
|
||||||
|
public static event EventHandler<ScheduledTaskStartedEventArgs>? TaskStarted;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Create a scheduled task
|
/// Create a scheduled task
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="task">The task to run</param>
|
/// <param name="taskFunc">The task to run</param>
|
||||||
/// <param name="runTime">The time to run the task</param>
|
/// <param name="runTime">The time to run the task</param>
|
||||||
/// <param name="customData">Any custom data you wish to provide.</param>
|
/// <param name="customData">Any custom data you wish to provide.</param>
|
||||||
/// <returns>An unique identifier of the task</returns>
|
/// <returns>An unique identifier of the task</returns>
|
||||||
|
|
||||||
public static string CreateScheduledTask(this Task task, DateTime runTime, object? customData = null)
|
public static string CreateScheduledTask(this Func<Task> taskFunc, DateTime runTime, object? customData = null)
|
||||||
{
|
{
|
||||||
if (task.Status != TaskStatus.Created)
|
|
||||||
throw new InvalidOperationException("The task is already being executed or has been scheduled for execution.")
|
|
||||||
.AttachData("Task", task)
|
|
||||||
.AttachData("RunTime", runTime)
|
|
||||||
.AttachData("CustomData", customData);
|
|
||||||
|
|
||||||
string UID = Guid.NewGuid().ToString();
|
string UID = Guid.NewGuid().ToString();
|
||||||
CancellationTokenSource CancellationToken = new CancellationTokenSource();
|
CancellationTokenSource CancellationToken = new CancellationTokenSource();
|
||||||
|
|
||||||
if (Math.Ceiling(runTime.GetTimespanUntil().TotalMilliseconds) < 0)
|
if (Math.Ceiling(runTime.GetTimespanUntil().TotalMilliseconds) < 0)
|
||||||
runTime = DateTime.UtcNow.AddSeconds(1);
|
runTime = DateTime.UtcNow.AddSeconds(1);
|
||||||
|
|
||||||
|
var scheduledTask = new ScheduledTask
|
||||||
|
{
|
||||||
|
Uid = UID,
|
||||||
|
RunTime = runTime,
|
||||||
|
TokenSource = CancellationToken,
|
||||||
|
CustomData = customData,
|
||||||
|
};
|
||||||
|
|
||||||
_ = LongDelay(runTime.GetTimespanUntil(), CancellationToken).ContinueWith(x =>
|
_ = LongDelay(runTime.GetTimespanUntil(), CancellationToken).ContinueWith(x =>
|
||||||
{
|
{
|
||||||
lock (RegisteredScheduledTasks)
|
lock (InternalScheduler.RegisteredScheduledTasks)
|
||||||
{
|
{
|
||||||
RegisteredScheduledTasks.Remove(UID);
|
InternalScheduler.RegisteredScheduledTasks.Remove(UID);
|
||||||
}
|
}
|
||||||
|
|
||||||
_logger?.LogDebug("Running scheduled task with UID '{UID}'", UID, runTime.GetTimespanUntil().GetHumanReadable());
|
_logger?.LogDebug("Running scheduled task with UID '{UID}'", UID, runTime.GetTimespanUntil().GetHumanReadable());
|
||||||
|
|
||||||
if (x.IsCompletedSuccessfully)
|
if (x.IsCompletedSuccessfully)
|
||||||
task.Start();
|
{
|
||||||
|
var task = Task.Run(taskFunc);
|
||||||
|
_ = Task.Run(() =>
|
||||||
|
{
|
||||||
|
ScheduledTaskExtensions.TaskStarted?.Invoke(null, new ScheduledTaskStartedEventArgs(scheduledTask, task));
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
lock (RegisteredScheduledTasks)
|
lock (InternalScheduler.RegisteredScheduledTasks)
|
||||||
{
|
{
|
||||||
_logger?.LogDebug("Creating scheduled task with UID '{UID}' running in {RunTime}", UID, runTime.GetTimespanUntil().GetHumanReadable());
|
_logger?.LogDebug("Creating scheduled task with UID '{UID}' running in {RunTime}", UID, runTime.GetTimespanUntil().GetHumanReadable());
|
||||||
|
InternalScheduler.RegisteredScheduledTasks.Add(UID, scheduledTask);
|
||||||
RegisteredScheduledTasks.Add(UID, new ScheduledTask
|
|
||||||
{
|
|
||||||
Uid = UID,
|
|
||||||
RunTime = runTime,
|
|
||||||
TokenSource = CancellationToken,
|
|
||||||
CustomData = customData,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
return UID;
|
return UID;
|
||||||
}
|
}
|
||||||
|
|
@ -60,18 +69,18 @@ public static class ScheduledTaskExtensions
|
||||||
/// <exception cref="KeyNotFoundException">Throws if the task hasn't been found or if an internal error occurred</exception>
|
/// <exception cref="KeyNotFoundException">Throws if the task hasn't been found or if an internal error occurred</exception>
|
||||||
public static void DeleteScheduledTask(string UID)
|
public static void DeleteScheduledTask(string UID)
|
||||||
{
|
{
|
||||||
if (!RegisteredScheduledTasks.ContainsKey(UID))
|
if (!InternalScheduler.RegisteredScheduledTasks.ContainsKey(UID))
|
||||||
throw new KeyNotFoundException($"No scheduled task has been found with UID '{UID}'");
|
throw new KeyNotFoundException($"No scheduled task has been found with UID '{UID}'");
|
||||||
|
|
||||||
if (RegisteredScheduledTasks[UID].TokenSource is null)
|
if (InternalScheduler.RegisteredScheduledTasks[UID].TokenSource is null)
|
||||||
throw new Exception($"Internal: There is no token source registered the specified task.");
|
throw new Exception($"Internal: There is no token source registered the specified task.");
|
||||||
|
|
||||||
_logger?.LogDebug("Deleting scheduled task with UID '{UID}'", UID);
|
_logger?.LogDebug("Deleting scheduled task with UID '{UID}'", UID);
|
||||||
|
|
||||||
lock (RegisteredScheduledTasks)
|
lock (InternalScheduler.RegisteredScheduledTasks)
|
||||||
{
|
{
|
||||||
RegisteredScheduledTasks[UID].TokenSource?.Cancel();
|
InternalScheduler.RegisteredScheduledTasks[UID].TokenSource?.Cancel();
|
||||||
RegisteredScheduledTasks.Remove(UID);
|
InternalScheduler.RegisteredScheduledTasks.Remove(UID);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -83,7 +92,7 @@ public static class ScheduledTaskExtensions
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>A list of all registered tasks</returns>
|
/// <returns>A list of all registered tasks</returns>
|
||||||
public static IReadOnlyList<ScheduledTask>? GetScheduledTasks()
|
public static IReadOnlyList<ScheduledTask>? GetScheduledTasks()
|
||||||
=> RegisteredScheduledTasks.Select(x => x.Value).ToList().AsReadOnly();
|
=> InternalScheduler.RegisteredScheduledTasks.Select(x => x.Value).ToList().AsReadOnly();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a specific task
|
/// Gets a specific task
|
||||||
|
|
@ -92,7 +101,7 @@ public static class ScheduledTaskExtensions
|
||||||
/// <returns>The task</returns>
|
/// <returns>The task</returns>
|
||||||
/// <exception cref="Exception">Throws if the task has not been found</exception>
|
/// <exception cref="Exception">Throws if the task has not been found</exception>
|
||||||
public static ScheduledTask GetScheduledTask(string UID)
|
public static ScheduledTask GetScheduledTask(string UID)
|
||||||
=> RegisteredScheduledTasks[UID];
|
=> InternalScheduler.RegisteredScheduledTasks[UID];
|
||||||
|
|
||||||
internal static async Task LongDelay(TimeSpan delay, CancellationTokenSource token)
|
internal static async Task LongDelay(TimeSpan delay, CancellationTokenSource token)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,4 @@ global using System.Drawing;
|
||||||
global using Microsoft.Extensions.Logging;
|
global using Microsoft.Extensions.Logging;
|
||||||
global using Xorog.UniversalExtensions.Enums;
|
global using Xorog.UniversalExtensions.Enums;
|
||||||
|
|
||||||
global using static Xorog.UniversalExtensions.Internal;
|
|
||||||
global using static Xorog.UniversalExtensions.InternalSheduler;
|
|
||||||
global using static Xorog.UniversalExtensions.Log;
|
global using static Xorog.UniversalExtensions.Log;
|
||||||
|
|
@ -1,4 +1,6 @@
|
||||||
namespace Xorog.UniversalExtensions;
|
using Xorog.UniversalExtensions.Entities;
|
||||||
|
|
||||||
|
namespace Xorog.UniversalExtensions;
|
||||||
|
|
||||||
internal static class Internal
|
internal static class Internal
|
||||||
{
|
{
|
||||||
|
|
@ -79,43 +81,9 @@ internal static class Internal
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class InternalSheduler
|
internal class InternalScheduler
|
||||||
{
|
{
|
||||||
public static Dictionary<string, ScheduledTask> RegisteredScheduledTasks { get; internal set; } = new Dictionary<string, ScheduledTask>();
|
public static Dictionary<string, ScheduledTask> RegisteredScheduledTasks { get; internal set; } = new Dictionary<string, ScheduledTask>();
|
||||||
|
|
||||||
public class ScheduledTask
|
|
||||||
{
|
|
||||||
public ScheduledTask()
|
|
||||||
{
|
|
||||||
this.Uid = Guid.NewGuid().ToString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The unique identifier of this task.
|
|
||||||
/// </summary>
|
|
||||||
public string Uid { get; internal set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The custom data asscociated with this task.
|
|
||||||
/// </summary>
|
|
||||||
public object? CustomData { get; internal set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The time this task will run.
|
|
||||||
/// </summary>
|
|
||||||
public DateTime? RunTime { get; internal set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The <see cref="CancellationTokenSource"/> to prematurely dequeue this task.
|
|
||||||
/// </summary>
|
|
||||||
internal CancellationTokenSource? TokenSource { get; set; } = new();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Delete this task.
|
|
||||||
/// </summary>
|
|
||||||
public void Delete() =>
|
|
||||||
ScheduledTaskExtensions.DeleteScheduledTask(Uid);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class HumanReadableTimeFormatConfig
|
public class HumanReadableTimeFormatConfig
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue