wcs_serve_wuxikate/Tools/CirculateTool/StartCirculation.cs
2025-01-03 14:36:27 +08:00

180 lines
6.5 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System.Reflection;
using CirculateTool.Attribute;
using CirculateTool.Entity;
namespace CirculateTool;
/*
* 作者:菻蔃
* 版本时间2023年04月15日
*
* 注意配合特性使用
*
*/
/// <summary>
/// 定时任务类
/// </summary>
public class StartCirculation
{
/// <summary>
/// 指定时间执行的方法类
/// </summary>
protected static List<TimeTask> _timeTasks = [];
/// <summary>
/// 触发的异常
/// </summary>
public event ExceptionHandlerEvent? ExceptionHandler;
public delegate void ExceptionHandlerEvent(string methodDescription, Exception ex);
/// <summary>
/// 显示相关信息
/// </summary>
public event MessageHandlerEvent? MessageHandler;
public delegate void MessageHandlerEvent(string message);
/// <summary>
/// 默认的循环时间
/// </summary>
private readonly int _defaultCirculationTime = 500;
/// <summary>
/// 启动一个程序集里面带有<see cref="CirculationAttribute"/>的类里面的定时方法
/// </summary>
/// <param name="assembly"></param>
/// <param name="instanceParams"></param>
public void StartAssemblyCirculation(Assembly assembly, object[]? instanceParams = null)
{
Type[] types = assembly.GetTypes();
if (types.Length == 0) return;
foreach (Type type in types)
{
var attributes = type.GetCustomAttributes(false);
foreach (var attribute in attributes)
{
if (attribute is not CirculationAttribute) continue;
StartTask(type, instanceParams);
break;
}
}
/* 执行按时执行的任务 ---- 方法内判断,若没有此类方法则不会执行 */
StartTimeTask();
}
/// <summary>
/// 开启一个实例里面所有已经添加了特性<see cref="CirculationAttribute"/>的方法
/// </summary>
/// <param name="type"></param>
/// <param name="instanceParams"></param>
public virtual void StartTask(Type type, object[]? instanceParams = null)
{
var methods = type.GetMethods();
foreach (var method in methods)
{
object[] attributes = method.GetCustomAttributes(false);
if(attributes.Length == 0) continue;
foreach (object attribute in attributes)
{
if(attribute == default) continue;
/* 定时执行的任务 */
if(attribute is CirculationAttribute needDurable)
{
string methodDescription = needDurable.MethodDescription ?? $"{type.Name}.{method.Name}";
bool Action() => (bool)(method.Invoke(Activator.CreateInstance(type, instanceParams), []) ?? false);
StartTask(Action, methodDescription, needDurable.CirculationTime);
break;
}
/* 每天指定时间执行 */
if (attribute is CirculationTimeAttribute timeCirculate)
{
string methodDescription = timeCirculate.MethodDescription ?? $"{type.Name}.{method.Name}";
MessageHandler?.Invoke($"定时器任务:{methodDescription},已经添加,执行时间为:{timeCirculate}");
foreach (var time in timeCirculate.Times)
{
_timeTasks.Add(new TimeTask
{
ExecuteTime = time,
Action = () => method.Invoke(Activator.CreateInstance(type, instanceParams), []),
Description = methodDescription,
IsRun = false
});
}
}
/* END */
}
}
}
/// <summary>
/// 开启一个方法 ---- 隔一定时间执行一次
/// </summary>
/// <param name="action"></param>
/// <param name="description"></param>
/// <param name="durableTime"></param>
/// <returns></returns>
public virtual async void StartTask(Func<bool> action, string? description = null, int? durableTime = null)
{
int durableTimeValue = durableTime ?? _defaultCirculationTime;
string methodDescription = description ?? action.Method.Name;
CancellationTokenSource cts = new();
PeriodicTimer timer = new(new TimeSpan(0, 0, 0, 0, durableTimeValue));
MessageHandler?.Invoke($"定时器:{methodDescription},已经启动,执行间隔为:{durableTimeValue} 毫秒。");
while (await timer.WaitForNextTickAsync(cts.Token))
{
try
{
var result = action();
if (result) continue;
await cts.CancelAsync();
MessageHandler?.Invoke($"定时器:{methodDescription},主动结束。");
return; // 该return会结束这个线程
}
catch (Exception ex)
{
ExceptionHandler?.Invoke(methodDescription, ex);
}
}
}
/// <summary>
/// 执行按时间执行的任务
/// </summary>
public virtual async void StartTimeTask()
{
if(_timeTasks.Count == 0) return;
CancellationTokenSource cts = new();
PeriodicTimer timer = new(new TimeSpan(0, 0, 0, 1, 0));
while (await timer.WaitForNextTickAsync(cts.Token))
{
string timeStr = DateTime.Now.ToString("HH:mm");
List<Task> taskList = [];
foreach (var task in _timeTasks)
{
taskList.Add(Task.Factory.StartNew(() =>
{
if (task.ExecuteTime != timeStr)
{
task.IsRun = false; // 当时刻不匹配时,重置任务状态
return;
}
if (task.ExecuteTime == timeStr && !task.IsRun) // 当时间匹配且任务未执行时,执行任务
{
try
{
task.Action!();
task.IsRun = true;
}
catch (Exception ex)
{
ExceptionHandler?.Invoke(task.Description ?? task.Action!.Method.Name, ex);
}
}
}));
}
Task.WaitAll([.. taskList]);
}
}
}