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
|
||||
{
|
||||
/// <summary>
|
||||
/// Fired when a log message has been sent.
|
||||
/// </summary>
|
||||
public static event EventHandler<ScheduledTaskStartedEventArgs>? TaskStarted;
|
||||
|
||||
/// <summary>
|
||||
/// Create a scheduled task
|
||||
/// </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="customData">Any custom data you wish to provide.</param>
|
||||
/// <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();
|
||||
CancellationTokenSource CancellationToken = new CancellationTokenSource();
|
||||
|
||||
if (Math.Ceiling(runTime.GetTimespanUntil().TotalMilliseconds) < 0)
|
||||
runTime = DateTime.UtcNow.AddSeconds(1);
|
||||
|
||||
var scheduledTask = new ScheduledTask
|
||||
{
|
||||
Uid = UID,
|
||||
RunTime = runTime,
|
||||
TokenSource = CancellationToken,
|
||||
CustomData = customData,
|
||||
};
|
||||
|
||||
_ = 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());
|
||||
|
||||
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());
|
||||
|
||||
RegisteredScheduledTasks.Add(UID, new ScheduledTask
|
||||
{
|
||||
Uid = UID,
|
||||
RunTime = runTime,
|
||||
TokenSource = CancellationToken,
|
||||
CustomData = customData,
|
||||
});
|
||||
InternalScheduler.RegisteredScheduledTasks.Add(UID, scheduledTask);
|
||||
}
|
||||
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>
|
||||
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}'");
|
||||
|
||||
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.");
|
||||
|
||||
_logger?.LogDebug("Deleting scheduled task with UID '{UID}'", UID);
|
||||
|
||||
lock (RegisteredScheduledTasks)
|
||||
lock (InternalScheduler.RegisteredScheduledTasks)
|
||||
{
|
||||
RegisteredScheduledTasks[UID].TokenSource?.Cancel();
|
||||
RegisteredScheduledTasks.Remove(UID);
|
||||
InternalScheduler.RegisteredScheduledTasks[UID].TokenSource?.Cancel();
|
||||
InternalScheduler.RegisteredScheduledTasks.Remove(UID);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
|
@ -83,7 +92,7 @@ public static class ScheduledTaskExtensions
|
|||
/// </summary>
|
||||
/// <returns>A list of all registered tasks</returns>
|
||||
public static IReadOnlyList<ScheduledTask>? GetScheduledTasks()
|
||||
=> RegisteredScheduledTasks.Select(x => x.Value).ToList().AsReadOnly();
|
||||
=> InternalScheduler.RegisteredScheduledTasks.Select(x => x.Value).ToList().AsReadOnly();
|
||||
|
||||
/// <summary>
|
||||
/// Gets a specific task
|
||||
|
|
@ -92,7 +101,7 @@ public static class ScheduledTaskExtensions
|
|||
/// <returns>The task</returns>
|
||||
/// <exception cref="Exception">Throws if the task has not been found</exception>
|
||||
public static ScheduledTask GetScheduledTask(string UID)
|
||||
=> RegisteredScheduledTasks[UID];
|
||||
=> InternalScheduler.RegisteredScheduledTasks[UID];
|
||||
|
||||
internal static async Task LongDelay(TimeSpan delay, CancellationTokenSource token)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -9,6 +9,4 @@ global using System.Drawing;
|
|||
global using Microsoft.Extensions.Logging;
|
||||
global using Xorog.UniversalExtensions.Enums;
|
||||
|
||||
global using static Xorog.UniversalExtensions.Internal;
|
||||
global using static Xorog.UniversalExtensions.InternalSheduler;
|
||||
global using static Xorog.UniversalExtensions.Log;
|
||||
|
|
@ -1,4 +1,6 @@
|
|||
namespace Xorog.UniversalExtensions;
|
||||
using Xorog.UniversalExtensions.Entities;
|
||||
|
||||
namespace Xorog.UniversalExtensions;
|
||||
|
||||
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 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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue