【导读】本节咱们继续稍微详细讲讲在我没有详细了解源码的前提下来探讨经过Hangfire定时触发做业有哪些须要注意的事项
间隔时间内执行做业git
举个栗子,每隔10秒监控系统CPU,若CPU飙高(根据实际业务定义百分比)则在控制台打印输出,第一次执行做业若CPU飙高则打印输出,但在接下来一分钟内CPU连续飙高则再也不打印,若中间有中断(CPU正常)则恢复正常打印,如此反复循环。github
通常来说定时做业都会执行业务,但上述栗子却根据做业内部逻辑判断是否执行打印,因此两者仍是有所区别web
接下来咱们一步步来进行大体模拟实现,首先咱们利用内存来存储做业相关操做,而后每隔10秒执行打印方法算法
_colorify = new Format(Theme.Dark);
GlobalConfiguration.Configuration.UseMemoryStorage();
using var server = new BackgroundJobServer();
RecurringJob.AddOrUpdate(() => Print(), "*/10 * * * * *", TimeZoneInfo.Local);
Console.ReadLine();
接下来则是执行上述打印方法
微信
public static void Print()
{
_colorify.WriteLine($"{DateTime.Now}:CPU飙高啦~~~", Colors.txtSuccess);
}
待执行做业方法必定要为公共(public)方法,不然会抛出以下异常并发
最后咱们每隔10秒执行一次做业看看打印输出时间是否如咱们所预期那样
app
虽然Hangfire从1.7+开始支持秒级,但对于做业默认的最小间隔时间是15秒,貌似是没法改变。因此上述咱们看到的做业间隔时间差是15秒而非10秒
编辑器
即便针对只触发一次做业设置为10秒也无济于事,不知道是否可改变,未深刻研究
ide
var options = new BackgroundJobServerOptions
{
SchedulePollingInterval = TimeSpan.FromMilliseconds(10)
};
BackgroundJob.Schedule(() => Print(), TimeSpan.FromSeconds(10));
以前咱们讲过若是利用SQLite存储做业那么将会出现重复并发执行的状况,比如咱们以下将其修改成SQLite存储性能
GlobalConfiguration.Configuration.UseSQLiteStorage("Data Source=./hangfire.db;");
此时毫无疑问会出现连续打印状况(在内存中也会偶尔出现,几率没有SQLit高)
如果必须限制在间隔时间内只能执行一次做业且在内存或SQLite中存储做业,那么咱们能够尝试使用限流算法(漏桶算法),在指定时间内只容许几个请求进入(算法参考地址:https://github.com/robertmircea/RateLimiters)
private static readonly FixedTokenBucket bucket = new FixedTokenBucket(1, 1, 10000);
实例化对应漏桶算法且在10秒内只能透传1个请求执行做业
public static void Print()
{
if (bucket.ShouldThrottle(1))
{
return;
}
_colorify.WriteLine($"{DateTime.Now}:CPU飙高啦~~~", Colors.txtSuccess);
}
若在10秒超过1个请求进入则当即返回
接下来咱们实如今1分钟内禁止连续打印CPU飙高的状况,首先咱们将1分钟内时间控制利用内存存储来实现
var provider = new ServiceCollection()
.AddMemoryCache()
.BuildServiceProvider();
cache = provider.GetService<IMemoryCache>();
而后咱们继续改造打印方法,在内存中记录第1次打印的时间,而后对比接下来1分钟的时间差,若小于则返回,不然打印再次存储打印的时间
public static void Print()
{
double totalMinutes = 0;
if (cache.TryGetValue("sys_alarm_time", out DateTime time))
{
var subtract = DateTime.Now.Subtract(time);
totalMinutes = subtract.TotalMinutes;
_colorify.WriteLine($"subtract:{totalMinutes}", Colors.txtInfo);
}
if ((int)totalMinutes < 1 && totalMinutes != 0)
{
return;
}
cache.Set("sys_alarm_time", DateTime.Now);
_colorify.WriteLine($"{DateTime.Now}:CPU飙高啦~~~", Colors.txtSuccess);
}
这里惟一须要注意的是在比较时间差1分钟,不能用Convert.ToInt32来进行强制转换
if (Convert.ToInt32(totalMinutes) < 1 && totalMinutes != 0)
{
return;
}
利用上述强制转换不能精确到接近于1分钟,由于它是银行家算法四舍五入,更贴切的说是四舍六入,好比为时间差为0.6时,通过强制转换后结果就为1,因此利用第一种强制转换则是只取整数部分
虽然说做业执行时间长短会略有差别,但利用第1种强制转换会控制时间差不会和1分钟相差太多
咱们看到上述时间间隔恰好是1分钟加上默认的时间间隔15秒,能作到这样基本上差很少了
本节咱们借助一个栗子主要讲述在控制台中执行存储在内存或SQLite中的做业,在实际项目中,使用Hangfire时或多或少都会存在一些问题
好比咱们是否考虑将做业存储在内存中,那么对于间隔时间很短的定时做业,是否会带来的很大的存储开销呢?理论上Hangfire会对其进行处理,又好比若是做业有几百个间隔时间很短的定时做业,那么Hangfire是否会存在性能问题呢?还有其余等在使用过程当中可能遇到的问题。
本文分享自微信公众号 - dotNET跨平台(opendotnet)。
若有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一块儿分享。