查看: 84|回复: 0

.NET 定时任务 FreeScheduler(开源内卷)

[复制链接]

3

主题

4

帖子

9

积分

新手上路

Rank: 1

积分
9
发表于 2023-3-29 15:31:57 | 显示全部楼层 |阅读模式
前言

.NET 定时组件生态实在太强大了,写下此文只希望能供大家多一个选择,不想重复造轮子,实在是事出有因。

高中读书那会,盛大传奇是最火爆的网络游戏,我和我的同学们都对它有过沉迷,甚至到上班几年之后,对它仍然有一种莫名的情怀。
干我们这行忙的时候要加班,闲的时候也很闲,在我曾经很闲的一份工作里,为了情怀去研究了传奇sf引擎,在简洁的脚本代码里我发现了一个宝藏:活动定时任务。除了以秒单位定时触发,还可以设置每月某天、每周某天、每天某时间,在 .net framework 3.0 普遍还在使用 Timer 的年代,我一下子被惊艳到了,于是利用 Timer 仿着功能自己实现了一版 .NET 定时任务功能类。
一开始只是一个类直接放进项目内使用,从未发布过 nuget 版本。打从 2016 年接触 .net core 以来,励志为开源生涯添砖加瓦,这才有了正式发布的念头。我曾经维护过 csredis(因原作者不维护所以发布为 CSRedisCore),呕心沥血从零到一开源 FreeSql,重构 RedisClient 发布的 FreeRedis,聊天架构 IMCore。。。等等。
因 FreeSql 使用需求编写了有趣的开源组件 IdleBus,写完后发现它的特点还蛮适合用来扩展定时任务,于时重构了一个版本命名 IdleScheduler,在 2020 年发布开源,前不久已正式改名为 FreeScheduler。
经历了十几年的使用需求和改造进化,实在是"食之无味,弃之可惜"。还是供大家多一个选择吧!
主要优势
FreeScheduler 轻量化定时任务调度,支持临时的延时任务和重复循环任务(可持久化),可按秒,每天/每周/每月固定时间,自定义间隔执行(CRON表达式),支持 .NET Framework 4.0,.NETCore2.1 +,Xamarin、MAUI 等平台 运行环境。
特色功能之一:持久化,比如创建订单半小时未支付,给用户催发短信,这种动态任务会用到技久化。
特色功能之二:FreeScheduler 支持一个任务设置 [5,5,30,30,60] 不同的定时间隔,任何一次成功都可结束整个任务。
scheduler.AddTask("比武大会","json",new[]{5,5,30,30,60});classMyTaskHandler:FreeScheduler.TaskHandlers.TestHandler{publicoverridevoidOnExecuting(Schedulerscheduler,TaskInfotask){Console.WriteLine($"[{DateTime.Now.ToString("HH:mm:ss.fff")}]{task.Topic}被执行");if(task.Topic=="比武大会"){try{//todo..//任何一次不报错,强制使任务完成task.Status=TaskStatus.Completed;}finaly{}}}}轻量化解释:了解 FreeRedis、FreeSql、csredis 的人都知道,我们发布的开源项目是绿色著称,零依赖发布后只有一个DLL,不会造成使用者项目依赖冲突,支持 .NET 4.0 堪称屎山项目的救星。现在还有很多.NET FX4.0 的项目,这些项目因历史遗留原因或硬件限制,不能更换 .NET Core 版本。
因此这些项目很难使用到现有的开源库,不能使用可靠的开源库,那么很多时候都要自行实现,在堆积代码的同时,项目也有可能越来越乱,代码越来越渣,项目逐渐变得不稳定。
快速开始
开源地址:https://github.com/2881099/FreeScheduler
演示代码:https://github.com/2881099/FreeScheduler/blob/master/Examples/Examples_FreeScheduler_WinformNet40/Form1.cs
dotnet add package FreeScheduler
或者
Install-Package FreeScheduler
publicstaticSchedulerscheduler=newScheduler(newMyTaskHandler());//单例模式,尽量保证只创建一次临时任务

临时任务属于内存任务,不可持久化。
voidCallback(){Console.WriteLine("时间到了");scheduler.AddTempTask(TimeSpan.FromSeconds(10),Callback);//设置下一次定时}scheduler.AddTempTask(TimeSpan.FromSeconds(10),Callback);//如果是一次性任务,可以这样写:scheduler.AddTempTask(TimeSpan.FromSeconds(10),()=>{Console.WriteLine("时间到了");});本地环境测试 50万 个临时任务,占用内存 383M,全部执行完成耗时 70秒。

  • http://Quartz.net 内存溢出,耗时 50秒
  • FluentScheduler 占用内存 1700M,耗时 未知
  • HashedWheelTimer 占用内存 213M,耗时 34秒
我尝试过把 FreeScheduler 内核改成 HashedWheelTimer 内存占用更高(600兆),原因是 FreeScheduler 功能需要占用更多资源。
循环任务

  • 临时任务是一次性触发,触发体是 Action 委托
  • 循环任务是周期性重复触发,触发体是 FreeScheduler.ITaskHandler,如上述 MyTestHandler
//每5秒触发,执行N次varid=scheduler.AddTask("topic1","body1",round:-1,5);//每次不同的间隔秒数触发,执行6次varid=scheduler.AddTask("topic1","body1",new[]{5,5,10,10,60,60});//每天20:00:00触发,指定utc时间,执行N次varid=scheduler.AddTaskRunOnDay("topic1","body1",round:-1,"20:00:00");//每周一20:00:00触发,指定utc时间,执行1次varid=scheduler.AddTaskRunOnWeek("topic1","body1",round:1,"1:20:00:00");//每月1日20:00:00触发,指定utc时间,执行12次varid=scheduler.AddTaskRunOnMonth("topic1","body1",round:12,"1:20:00:00");Cron

由于 .NET Cron 组件普遍不支持年,因此 FreeScheduler 默认没有集成,但是很容易扩展实现,如下:
varid=scheduler.AddTaskCustom("topic1","body1","0/1****?");publicstaticSchedulerscheduler=newScheduler(newMyTaskHandler(),newCronCustomHandler());//单例模式,尽量保证只创建一次classCronCustomHandler:FreeScheduler.ITaskIntervalCustomHandler{publicTimeSpan?NextDelay(TaskInfotask){//利用cron功能库解析task.IntervalArgument得到下一次执行时间//与当前时间相减,得到TimeSpan,若返回null则任务完成returnTimeSpan.FromSeconds(5);}}持久化

FreeScheduler 把任务分为两种类型,临时任务和循环任务,注意临时任务不支持持久化。
当前已支持 数据库或Redis 持久化实现,各有优缺点:

  • 数据库,性能低,方便接入任务管理(后台管理系统)
  • Redis,性能高,由于分页的特点,接入任务管理功能略难
使用持久化只需要把 Scheduler 构造参数修改,如下:
varfsql=newFreeSql.FreeSqlBuilder().UseConnectionString(FreeSql.DataType.Sqlite,"datasource=task.db;maxpoolsize=5").UseAutoSyncStructure(true).UseNoneCommandParameter(true).UseMonitorCommand(cmd=>Console.WriteLine($"=========sql:{cmd.CommandText}\r\n")).Build();Schedulerscheduler=newScheduler(newMyTaskHandler(fsql));classMyTaskHandler:FreeScheduler.TaskHandlers.FreeSqlHandler{publicMyTaskHandler(IFreeSqlfsql):base(fsql){}publicoverridevoidOnExecuting(Schedulerscheduler,TaskInfotask){Console.WriteLine($"[{DateTime.Now.ToString("HH:mm:ss.fff")}]{task.Topic}被执行");}}Redis 持久化请安装:
dotnet add package FreeScheduler.TaskHandlers.FreeRedis

Install-Package FreeScheduler.TaskHandlers.FreeRedis
管理任务

//使用FreeSql或者SQL查询TaskInfo、TaskLog两个表进行分页显示fsql.Select<TaskInfo>().Count(outvartotal).Page(pageNumber,30).ToList();fsql.Select<TaskLog>().Count(outvartotal).Page(pageNumber,30).ToList();//暂停任务scheduler.PauseTask(id);//恢复暂停的任务scheduler.ResumeTask(id);//删除任务scheduler.RemoveTask(id);性能参考

FluentScheduler 单个 Registry 测试正常,但目测单线程执行(间隔1-10ms),处理速度不理想(https://github.com/2881099/FreeScheduler/blob/master/Examples/Examples_FreeScheduler_VsQuartz/Program.cs)
我尝试把 FreeScheduler 内核改成 HashedWheelTimer 内存占用更高(600兆),结论:FreeScheduler 功能需要占用更多资源
结束语
.NET 定时任务组件太多了,以至于过去这些年都还没有正式推广过,希望能帮助到有需求的朋友。
开源地址:https://github.com/2881099/FreeScheduler
作者是什么人?
作者是一个入行 18年的老批,他目前写的.NET开源项目有:
需要的请拿走,这些都是最近几年的开源作品,以前更早写的就不发了。
转自:FreeSql
链接:http://cnblogs.com/FreeSql/p/16623030.html
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

快速回复 返回顶部 返回列表