定时调度插件------Longbow.Tasks
使用说明
dll引用
-
使用NuGet 搜索Longbow.Task可找到相关版本的dll
目前最新的为7.0.0版本,需net6.0+
如果低版本用户可使用5.2.1
-
直接下载源码编译即可
dll引入程序
- .netcore 容器注入
services.AddTaskServices();
- donet4.5+ 使用
// 程序入口调用
TaskServicesManager.Init();
自定义业务实现(Job)
-
自定义业务类
/// <summary> /// 后台任务实现类 /// </summary> public class FooTask : ITask { /// <summary> /// 后台任务具体业务操作 /// </summary> public async Task Execute(CancellationToken cancellationToken) { // 模拟任务执行耗时500毫秒 try { await Task.Delay(500, cancellationToken); } catch (TaskCanceledException) { } if (cancellationToken.IsCancellationRequested) { return; } // do something ... } }
-
将自定义业务类添加到程序中
// 1.将FooTask添加,默认使用内部的触发器 TaskServicesManager.GetOrAdd<FooTask>().Task.Execute(default); // 2.设置触发器Cron // 每分钟的第 5 秒循环执行任务 TaskServicesManager.GetOrAdd<FooTask>("表达式任务", token => Task.Delay(1000), TriggerBuilder.Build("5 * * * * *"));
测例代码说明
CronTest测例
-
DateTimeOffset 与DateTime的不同:多存储了时区
-
通过Cron类来获得下次执行的时间
var now = DateTimeOffset.Now; // 1.当前时间加5s与后者相等 // Cron.Secondly():返回Cron的string // ParseCronExpression(): 将string转换为CronExpression // GetNextExecution:通过参数的时间来获得下次执行的时间 Assert.Equal(now.AddSeconds(5), Cron.Secondly(5).ParseCronExpression().GetNextExecution(now)); // 2.每 2 秒 执行一次 var cron = "*/2 * * * * *".ParseCronExpression(); // 获取一个一分钟之内的任务列表 var nextRuntimes = cron.GetOccurrences(now, now.AddMinutes(1), TimeZoneInfo.Local).Take(3).ToList(); // 每个任务间隔时间为2s Assert.Equal(nextRuntimes[0].AddSeconds(2), nextRuntimes[1]); Assert.Equal(nextRuntimes[1].AddSeconds(2), nextRuntimes[2]); // 3.cron必须按照时间规格来设置,不能超过
DictionaryTest测例
// ConcurrentDictionary进行AddOrUpdate时,如果内部使用了并发代码,需要使用懒加载模式
var tasks = Enumerable.Range(1, 5).Select(i => Task.Run(() =>
{
var temp = pool.AddOrUpdate("Test", key => new Lazy<string>(() =>
{
var t = GenerateValue(i); //返回的为Task<string>
t.Wait();
return t.Result;
}), (key, value) => new Lazy<string>(() =>
{
var t = UpdateValue(i); //返回的为Task<string>
t.Wait();
return t.Result;
}));
}));
ScheduleTaskTest测例
// 1.CancellationTokenSource的WaitOne方法
var cts = new CancellationTokenSource();
// 返回false表示2s已经过去,任务未结束
Assert.False(cts.Token.WaitHandle.WaitOne(2000));
// 1s后结束任务
cts.CancelAfter(1000);
// 返回true,表示2s内任务已经结束
Assert.True(cts.Token.WaitHandle.WaitOne(2000));
// 2.TriggerBuilder触发器
// 每秒执行一次,无超时时间,从当前时间开始,第三个参数可为空,表示当前时间
TriggerBuilder.Build(Cron.Secondly(), -1, DateTimeOffset.Now);
// 创建当前时间的触发器
TriggerBuilder.Default.WithStartTime().Build();
// 以1000毫秒为周期的触发器
TriggerBuilder.Default.WithInterval(1000).Build();
// 设置超时时间为1s,第二个参数不设置则为Timeout.InfiniteTimeSpan
TriggerBuilder.Build(Cron.Secondly(), 1000);
TaskManagerTest测例
// 1.开始任务
// Foo2Task重载ExecutableTask方法并实现ConfigureStartInfo接口
// Command和Argumens为命令行的相关参数
var sche = TaskServicesManager.GetOrAdd<Foo2Task>();
await Task.Delay(300);
// 执行
await sche.Task.Execute(default);
// 2.触发器执行后的回调函数
sche.Triggers.First().PulseCallback = t =>{};
TaskStorageTest测例
// 1.当持久化以后,再次GetOrAdd时任务体不会被执行
TaskServicesManager.GetOrAdd("StorageRunOnce", token =>
{
return Task.CompletedTask;
});
// 2.利用发射获得 IStorage 实例
var factory = typeof(TaskServicesManager).GetProperty("Factory", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic);
var instance = factory.GetValue(null, null);
var storageInstance = instance.GetType().GetProperty("Storage").GetValue(instance);
var option = storageInstance.GetType().GetProperty("Options").GetValue(storageInstance) as FileStorageOptions;
option.DeleteFileByRemoveEvent = true;
TaskServicesManager.Clear();
option.DeleteFileByRemoveEvent = false;
相关文档
Wiki: 传送门