乐趣区

关于.net:开源精品-NET-定时任务-FreeScheduler-支持-cron持久化可变定时设置

💻 前言

卷了,卷了,卷了,最近太卷。。。这篇文章写了好几天了,因为同类型文章太多,排期到明天公布。切实不想卷,得罪了!各位定时工作开源大佬们!

.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});

class MyTaskHandler : FreeScheduler.TaskHandlers.TestHandler
{public override void OnExecuting(Scheduler scheduler, TaskInfo task)
    {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/Fr…

dotnet add package FreeScheduler

或者

Install-Package FreeScheduler

public static Scheduler scheduler = new Scheduler(new MyTaskHandler()); // 单例模式,尽量保障只创立一次 

📡 长期工作

长期工作属于内存工作,不可长久化。

void Callback()
{Console.WriteLine("工夫到了");
    scheduler.AddTempTask(TimeSpan.FromSeconds(10), Callback); // 设置下一次定时
}
scheduler.AddTempTask(TimeSpan.FromSeconds(10), Callback);

// 如果是一次性工作,能够这样写:scheduler.AddTempTask(TimeSpan.FromSeconds(10), () =>
{Console.WriteLine("工夫到了");
});
Method 阐明
string AddTempTask(TimeSpan, Action) 创立长期的延时工作,返回 id
bool RemoveTempTask(string id) 删除工作 (长期工作)
bool ExistsTempTask(string id) 判断工作是否存在 (长期工作)
int QuantityTempTask 工作数量 (长期工作)

本地环境测试 50 万 个长期工作,占用内存 383M,全副执行实现耗时 70 秒。

  • Quartz.net 内存溢出,耗时 50 秒
  • FluentScheduler 占用内存 1700M,耗时 未知
  • HashedWheelTimer 占用内存 213M,耗时 34 秒

我尝试过把 FreeScheduler 内核改成 HashedWheelTimer 内存占用更高 (600 兆),起因是 FreeScheduler 性能须要占用更多资源。


🎣 循环工作

  • 长期工作是一次性触发,触发体是 Action 委托
  • 循环工作是周期性反复触发,触发体是 FreeScheduler.ITaskHandler,如上述 MyTestHandler
Method 阐明
void ctor(ITaskHandler) 指定任务调度器(单例)
string AddTask(string topic, string body, int round, int seconds) 创立循环定时工作,返回 id
string AddTask(string topic, string body, int[] seconds) 创立每轮距离不同的定时工作,返回 id
string AddTaskRunOnDay(..) 创立每日循环工作,指定 utc 工夫,返回 id
string AddTaskRunOnWeek(..) 创立每周循环工作,指定 utc 工夫,返回 id
string AddTaskRunOnMonth(..) 创立每月循环工作,指定 utc 工夫,返回 id
string AddTaskCustom(string topic, string body, string expression) 创立自定义工作,返回 id
bool RemoveTask(string id) 删除工作
bool ExistsTask(string id) 判断工作是否存在
bool ResumeTask(string id) 复原已暂停的工作
bool PauseTask(string id) 暂停正在运行的工作
TaskInfo[] FindTask(lambda) 查问正在运行中的工作
int QuantityTask 工作数量
// 每 5 秒触发,执行 N 次
var id = scheduler.AddTask("topic1", "body1", round: -1, 5);

// 每次 不同的距离秒数触发,执行 6 次
var id = scheduler.AddTask("topic1", "body1", new [] {5, 5, 10, 10, 60, 60});

// 每天 20:00:00 触发,指定 utc 工夫,执行 N 次
var id = scheduler.AddTaskRunOnDay("topic1", "body1", round: -1, "20:00:00");

// 每周一 20:00:00 触发,指定 utc 工夫,执行 1 次
var id = scheduler.AddTaskRunOnWeek("topic1", "body1", round: 1, "1:20:00:00");

// 每月 1 日 20:00:00 触发,指定 utc 工夫,执行 12 次
var id = scheduler.AddTaskRunOnMonth("topic1", "body1", round: 12, "1:20:00:00");

🌈 Cron

因为 .NET Cron 组件广泛不反对年,因而 FreeScheduler 默认没有集成,然而很容易扩大实现,如下:

var id = scheduler.AddTaskCustom("topic1", "body1", "0/1 * * * * ?");

public static Scheduler scheduler = new Scheduler(new MyTaskHandler(), new CronCustomHandler()); // 单例模式,尽量保障只创立一次
class CronCustomHandler : FreeScheduler.ITaskIntervalCustomHandler
{public TimeSpan? NextDelay(TaskInfo task)
    {
        // 利用 cron 性能库解析 task.IntervalArgument 失去下一次执行工夫
        // 与以后工夫相减,失去 TimeSpan,若返回 null 则工作实现
        return TimeSpan.FromSeconds(5);
    }
}

🌳 长久化

FreeScheduler 把工作分为两种类型,长期工作和循环工作,留神长期工作不反对长久化。

以后已反对 数据库或 Redis 长久化实现,各有优缺点:

  • 数据库,性能低,不便接入工作治理(后盾管理系统)
  • Redis,性能高,因为分页的特点,接入工作治理性能略难

应用长久化只须要把 Scheduler 结构参数批改,如下:

var fsql = new FreeSql.FreeSqlBuilder()
    .UseConnectionString(FreeSql.DataType.Sqlite, "data source=task.db;max pool size=5")
    .UseAutoSyncStructure(true)
    .UseNoneCommandParameter(true)
    .UseMonitorCommand(cmd => Console.WriteLine($"=========sql: {cmd.CommandText}\r\n"))
    .Build();
Scheduler scheduler = new Scheduler(new MyTaskHandler(fsql));

class MyTaskHandler : FreeScheduler.TaskHandlers.FreeSqlHandler
{public MyTaskHandler(IFreeSql fsql) : base(fsql) { }

    public override void OnExecuting(Scheduler scheduler, TaskInfo task)
    {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(out var total).Page(pageNumber, 30).ToList();
fsql.Select<TaskLog>().Count(out var total).Page(pageNumber, 30).ToList();

// 暂停工作
scheduler.PauseTask(id);
// 复原暂停的工作
scheduler.ResumeTask(id);
// 删除工作
scheduler.RemoveTask(id);

🌴 性能参考

FreeScheduler Quartz.net FluentScheduler HashedWheelTimer
(500,000 Tasks + 10s) (500,000 Tasks + 10s) (500,000 Tasks + 10s) (500,000 Tasks + 10s)
383M 1700+M StackOverflow 213M
70563.6066ms 50692.5365ms 未知 33697.8758ms

FluentScheduler 单个 Registry 测试失常,但目测单线程执行 (距离 1 -10ms),处理速度不现实 View Code

我尝试把 FreeScheduler 内核改成 HashedWheelTimer 内存占用更高 (600 兆),论断:FreeScheduler 性能须要占用更多资源


🌌 结束语

.NET 定时工作组件太多了,以至于过来这些年都还没有正式推广过,心愿能帮忙到有需要的敌人。

开源地址:https://github.com/2881099/FreeScheduler


作者是什么人?

作者是一个入行 18 年的老批,他目前写的.net 开源我的项目有:

开源我的项目 形容 开源地址 开源协定
ImCore 聊天零碎架构 https://github.com/2881099/im MIT
FreeRedis Redis SDK https://github.com/2881099/Fr… MIT
csredis https://github.com/2881099/cs… MIT
FightLandlord 斗 DI 主网络版 https://github.com/2881099/Fi… 学习用处
FreeScheduler 定时工作 https://github.com/2881099/Fr… MIT
IdleBus 闲暇容器 https://github.com/2881099/Id… MIT
FreeSql ORM https://github.com/dotnetcore… MIT
FreeSql.Cloud 分布式 tcc/saga https://github.com/2881099/Fr… MIT
FreeSql.AdminLTE 低代码后盾生成 https://github.com/2881099/Fr… MIT
FreeSql.DynamicProxy 动静代理 https://github.com/2881099/Fr… 学习用处

须要的请拿走,这些都是最近几年的开源作品,以前更早写的就不发了。

退出移动版