You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何检查Hangfire循环任务是否正在运行以避免重复执行?

嘿,我之前在做Hangfire后台任务的时候也遇到过一模一样的需求——循环任务绝对不能同时跑两个实例,尤其是任务执行时间长的时候,得先检查有没有在运行,没在运行再执行。给你几个亲测有效的解决方案:

解决Hangfire循环任务禁止并发执行的实用方案

1. 用官方自带的DisableConcurrentExecution特性(最省心)

这是Hangfire官方为这类场景准备的特性,直接给你的任务方法加上就行,还能设置一个超时时间(比如60秒,超过这个时间Hangfire会判定之前的任务已经异常终止,允许新任务启动)。代码示例:

[DisableConcurrentExecution(60)] // 60秒超时阈值
public void LongRunningRecurringJob()
{
    // 这里写你的耗时任务逻辑
}

加了这个特性之后,Hangfire会自动帮你管控:如果同名任务当前正在运行,新的触发请求会直接跳过,完全不用自己写检查逻辑。

2. 手动查询任务运行状态(自定义控制)

要是你需要更灵活的判断逻辑,比如根据任务的特定标识来检查,那就可以用Hangfire的Monitoring API手动查询当前的运行任务列表。示例代码:

using Hangfire;
using Hangfire.States;

// 检查指定任务是否正在运行的方法
private bool IsTargetJobRunning()
{
    var monitoringApi = JobStorage.Current.GetMonitoringApi();
    // 获取所有正在运行的任务(0表示从第一个开始,int.MaxValue表示取全部)
    var runningJobs = monitoringApi.RunningJobs(0, int.MaxValue);
    
    // 这里可以根据任务方法名、自定义参数等条件过滤
    return runningJobs.Any(job => job.Value.Job.Method.Name == nameof(LongRunningRecurringJob));
}

// 调度任务前先检查
public void ScheduleRecurringJob()
{
    var jobId = "my-long-running-recurring-job";
    if (!IsTargetJobRunning())
    {
        RecurringJob.AddOrUpdate(jobId, () => LongRunningRecurringJob(), Cron.Hourly);
    }
}

注意哦,循环任务每次执行都会生成新的JobId,所以用方法名或者任务的唯一标识来过滤会更靠谱。

3. 分布式锁(多服务器部署场景必备)

如果你的Web应用是多服务器集群部署,上面两种方法可能会有漏网之鱼,这时候就得用分布式锁来确保全局唯一执行。Hangfire本身支持基于存储的分布式锁,比如用Redis做存储的话,直接这样写:

public void LongRunningRecurringJob()
{
    // 申请分布式锁,锁的有效期设为任务最长执行时间的上限
    using (var lockHandle = JobStorage.Current.AcquireDistributedLock("unique-job-lock-key", TimeSpan.FromMinutes(30)))
    {
        // 你的耗时任务逻辑写在这里
    }
}

这个锁会在整个集群范围内生效,不管多少台服务器,同一时间只会有一个任务实例在跑,彻底解决多节点的并发问题。

内容的提问来源于stack exchange,提问作者Wesley Skeen

火山引擎 最新活动