Hangfire单实例循环作业

19

我正在尝试使用Hangfire在后台运行一个定期任务,该任务从另一个网站轮询数据,问题是如果上一个任务仍在运行,我不希望定期任务运行。

我已经阅读了文档,但似乎找不到答案。是否有一种方法可以定期运行每10分钟的任务,但仅在前一个任务完成后才跳过?

public void Configuration(IAppBuilder app)
{
    app.MapSignalR();

    // Hangfire
    GlobalConfiguration.Configuration
        .UseSqlServerStorage("DatabaseContext");

    app.UseHangfireDashboard();
    app.UseHangfireServer();

    RecurringJob.AddOrUpdate("site-parser", () => SiteParserService.RunAll(), Cron.Minutely, TimeZoneInfo.Utc);

    ConfigureAuth(app);
}

1
这里有一个建议:将作业排队为单个实例。然后,如果作业成功完成,您可以在作业中执行最后一步。作业的最后一步将会在10分钟后再次排队执行。这样不就提供了您所需的功能吗? - Klaus Barkhausen
你是指相同的定期任务的最后一次执行吗? - andrei.ciprian
2个回答

10

1
我的解决方案:
namespace MyNameSpace
{
    public delegate void LockWrapperDelegateVoid();

    /* Job Locker. One job can work at current moment. Different jobs can work parallel */
    public static class JobLocker
    {
        private static readonly ConcurrentDictionary<string, bool> _locks = new ConcurrentDictionary<string, bool>();

        private static string LocksTryAdd(string lockerName)
        {
            if (string.IsNullOrEmpty(lockerName))  // lock by procedure's name (in this example = "JobProcedure")
            {
                lockerName = new StackFrame(2).GetMethod().Name;
            }
            if (!_locks.ContainsKey(lockerName))
            {
                _locks.TryAdd(lockerName, false);
            }
            return lockerName;
        }

        public static void LockWrapperVoid(string lockerName, LockWrapperDelegateVoid lockWrapperDelegateVoid)
        {
            lockerName = LocksTryAdd(lockerName);
            if (!_locks[lockerName])
            {
                _locks[lockerName] = true;
                try
                {
                    lockWrapperDelegateVoid();
                }
                finally
                {
                    _locks[lockerName] = false;
                }
            }
        }
    }
}

// USING

// JOB description
TryAddOrUpdateJob("JOB TITLE", () => JobManager.JobProcedure(), "* * * * *", TimeZoneInfo.Utc, "queueDefault");  // every one minute


public static void JobProcedure()
{
    // very important. You can use "BlockArea" instead null and use one area if several jobs depend each other
    // if null - area will have name like as the procedure ("JobProcedure")
    JobLocker.LockWrapperVoid(null, () =>  
    {
        //your code here
        System.Threading.Thread.Sleep(2 * 1000 * 60); // timeout - 2 minutes
    });
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接