c# - Hangfire 使用 MongoDB 执行长时间运行的后台作业不断重启

标签 c# asp.net mongodb background-process hangfire

我在使用 1.6.19 版 atm 和 MongoDB 作为存储的 Hangfire 时遇到问题,我们目前有一个方法,安排如下:

BackgroundJob.Schedule(() => DoAsyncTask(parameters, JobCancellationToken.Null), TimeSpan.FromMinutes(X))

该任务将运行一个多小时,它包含一个循环来验证作业何时完成。在循环内,调用 cancellationToken.ThrowIfCancellationRequested() 以验证是否已请求取消,但此调用在执行后大约 30 分钟后一直被触发,并在完成前终止作业。

我一直在搜索有关此问题的信息,但其中大部分与旧版本或根据 this answer 的 InvisibilityTimeout 的使用有关已被弃用,所以我想知道是否还有其他人遇到过此问题以及任何可能的解决方案。

谢谢

编辑:经过进一步调查,我发现取消问题只是运行 30 分钟后 HangFire 再次调用任务的副作用,因为我在方法中设置了验证以避免重新进入该过程仍在运行(以避免数据重复),该过程将被视为已完成并因此被取消。

所以我面临的真正问题是我无法确定 HangFire 在执行大约 30 分钟后再次调用进程的原因,我按照描述的步骤 here 进行操作将 IIS 上的应用程序设置为始终运行并防止池被回收,但行为仍然存在。

最佳答案

针对我的问题实现的解决方案是使用 this filter在作业上设置分布式锁,直到它正确完成。我对实现进行了一些小的更改,以包含作业 ID 并更新了对该版本 HangFire 上使用的新对象的调用,因此我将其保留在这里:

public class SkipConcurrentExecutionAttribute : JobFilterAttribute, IServerFilter
{
    private static readonly Logger logger = LogManager.GetCurrentClassLogger();

    private readonly int _timeoutInSeconds;

    public SkipConcurrentExecutionAttribute(int timeoutInSeconds)
    {
        if (timeoutInSeconds < 0) throw new ArgumentException("Timeout argument value should be greater that zero.");

        _timeoutInSeconds = timeoutInSeconds;
    }


    public void OnPerforming(PerformingContext filterContext)
    {
        var resource = $"{filterContext.BackgroundJob.Job.Type.FullName}.{filterContext.BackgroundJob.Job.Method.Name}.{filterContext.BackgroundJob.Id}";

        var timeout = TimeSpan.FromSeconds(_timeoutInSeconds);

        try
        {
            var distributedLock = filterContext.Connection.AcquireDistributedLock(resource, timeout);
            filterContext.Items["DistributedLock"] = distributedLock;
        }
        catch (Exception)
        {
            filterContext.Canceled = true;
            logger.Warn("Cancelling run for {0} job, id: {1} ", resource, filterContext.BackgroundJob.Id);
        }
    }

    public void OnPerformed(PerformedContext filterContext)
    {
        if (!filterContext.Items.ContainsKey("DistributedLock"))
        {
            throw new InvalidOperationException("Can not release a distributed lock: it was not acquired.");
        }

        var distributedLock = (IDisposable)filterContext.Items["DistributedLock"];
        distributedLock.Dispose();
    }
}

所以现在对后台进程的调用是:

[SkipConcurrentExecution(300)]
public async Task DoAsyncTask(parameters, IJobCancellationToken cancellationToken){
    //code execution here
}

我希望这会有所帮助,重新进入的原因仍然未知,因此请随时使用您可能找到的任何信息来扩展此答案。

关于c# - Hangfire 使用 MongoDB 执行长时间运行的后台作业不断重启,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51241124/

相关文章:

c# ListView.Items[i].remove 很慢

javascript - 无法调用undefined的save方法。蒙古人

javascript - 在 mongodb 中,从文档中获取单个字段的数组的最简单方法是什么

c# - ItemCommand 未在 Repeater 或 GridView 中首次单击时触发

c# - 管理 EntityConnection 生命周期

node.js - 我可以在 MongoDB 的聚合查询中申请 forEach 吗?

c# - 仍然可以在 C# 中选中已禁用的复选框

c# - 使用 WebClient 下载时防止服务器以 gzip 编码

c# - 如何将 HTML 传递给 Razor 局部 View ?

javascript - 将 VB.net aspx Web 应用程序中的 XML 文件保存到文件夹