HangFire循环作业中作业因执行时间太长未完成新作业开启导致重复数据的问题...

Posted dotNET跨平台

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了HangFire循环作业中作业因执行时间太长未完成新作业开启导致重复数据的问题...相关的知识,希望对你有一定的参考价值。

背景

HangFire有个很奇怪的现象,就是即使你设置的循环作业是一天一次,但是每次作业执行很长时间,我们假设是1小时,那么差不多在开始执行之后的30分钟之后,如果还在执行job,系统就会自动帮你重新开启了新的job执行。也就是撇开循环周期的影响,我一个长时间的作业,超过三十分钟的,那么系统又会在你还在执行的时候,三十分钟之后又起一个来帮你执行。

问题窥探

我之前做项目的时候,就遇到这个问题,莫名其妙。开始的时候,我还以为可以像Quartz加个[DisallowConcurrentExecution]了事。

后面找到这个

但是测试了下,不起作用啊。而且一旦启用分布式部署,这个就算有用,到时候不也没用了,后面想想直接来个干脆的,分布式锁。

解决办法

1、进入job的时候,定义一个key,判断是否正在执行。

    string uniqueKey = string.Empty;
            string key = "xxxxx";
            if (!CacheExtension.getInstance().AddUnique($"{key}_unique", 1, DateTimeOffset.Now.AddDays(365)))
            {
                LogExtention.getInstance().WriteCustomLogAsync("", "", true, "上批次还未执行结束--xxxxxxjob");
                return;
            }
            uniqueKey = $"{key}_unique";

2、redis-StringSet保证key是唯一的。

  /// <summary>
        /// 新增,若缓存中已存在相同KEY,则返回false,判断高并发时使用
        /// </summary>
        public bool AddUnique(string key, object o, DateTimeOffset expiration, string dependsOnKey = null)
        {
            key = AddSysCustomKey(key);
            var ts = expiration - DateTimeOffset.Now;
            return _client.StringSet(key, ConvertJson(o), ts, When.NotExists);
        }

3、执行完成的时候,去掉锁。

  try
            {
            //todo            
            }
            finally
                        { 
‍                ‍
                    CacheExtension.getInstance().Remove(uniqueKey);


            }

总结

1、这样的话,就能在旧的还未完成之前,新的进来,直接return,保证唯一性,也支持了分布式处理。

2、分布式锁在很多场景,还是很实用的。

以上是关于HangFire循环作业中作业因执行时间太长未完成新作业开启导致重复数据的问题...的主要内容,如果未能解决你的问题,请参考以下文章

使用 Hangfire 创建重复作业时出错

是什么原因导致天蓝色托管的hangfire作业具有这种行为?

应用程序池回收后,Hangfire 重复作业停止

是否可以使用 dotNet 使用 Hangfire 每 20 秒运行一次作业?

当 Hangfire 并行处理多个作业时,为啥 MySQL InnoDB 会产生如此多的死锁?

在与排队的用户不同的进程中运行后台作业