【问题标题】:Hangfire ContinueWithJob is stuck in awaiting state, though parent job has succeededHangfire ContinueWithJob 卡在等待状态,尽管父作业已成功
【发布时间】:2020-06-30 23:01:42
【问题描述】:

我通过ContinueJobWith<MyHandler>(parentJobId, x => x.DoWork()) 一个接一个地执行了一些工作。

但是,第二个作业没有得到处理,并且始终处于 Awaiting 状态:

工作本身是这样的:

为什么会发生这种情况以及在哪里检查结果?

  • 我们使用 Autofac 作为 DI 容器,但我们有自己的 JobActivator 实现,因为我们必须处理多租户。
  • 我们使用 SQL Server 2019 进行存储。
  • Hangfire 版本为 1.7.10
  • 这是 MVC 5 应用程序
  • 我没有在任何日志中或在调试期间看到任何错误/异常
  • 通过this 之后,我已将此添加到我们的 Autofac 注册中
            builder.RegisterType<BackgroundJobStateChanger>()
                   .As<IBackgroundJobStateChanger>()
                   .InstancePerLifetimeScope();

这没什么区别。

这是作业的执行方式:

var parentJobId = _backgroundJobClient.Schedule<Handler>(h => h.ConvertCertToTraining(certId, command.SetUpOneToOneRelationship), TimeSpan.FromSeconds(1));
var filesCopyJObId = _backgroundJobClient.ContinueJobWith<Handler>(parentJobId, h => h.CopyAttachedFiles());
_backgroundJobClient.ContinueJobWith<Handler>(filesCopyJObId, h => h.NotifyUser(command.CertificationToBeConvertedIds, _principal.GetEmail()));

所有参数都是intboolstring。如果我手动将等待的作业排入队列,它们将毫无问题地执行。

我添加了 Hangfire 日志记录,但在那里看不到任何问题:服务器启动、停止、作业更改状态,但在那里看不到任何明显的错误。

我应该考虑哪些其他事情或者我应该在哪里/如何调试这个?

【问题讨论】:

  • 您可以在作业中生成一些日志,以便您分析以了解发生了什么。
  • @ChetanRanpariya 检查他们。没有例外,没有其他关于可能导致这种情况的提示。我可以看到父作业经过阶段并最终被处理,但没有别的。

标签: c# hangfire


【解决方案1】:

从外观上看,第一个 ID 为 216348 的作业已成功完成,但您的第二个 ID 为 216349 的作业正在等待父 ID 为 216347。根据 Hangfire 文档和经验,parentID 应该是您在执行第二个作业之前等待完成的作业。

根据Hangfire documentation on ContinueJobWith,“继续在其父作业完成时执行”。从您的屏幕截图中,不清楚 JobID 发生了什么:216347。一旦这项工作,216347 完成,ID 为 216349 的工作应该开始。如果您希望 216349216348 完成后开始,请检查您的代码并确保将正确的 ParentID 传递给第二个作业。


更新

基于on this thread,将ContinuationsSupportAttribute 添加到您配置Hangfire 服务的GlobalJobFilters.Filter。这应该让您的 Hangfire 实例知道延续作业。

GlobalJobFilters.Filters.Add(new ContinuationsSupportAttribute());

【讨论】:

  • 双重检查 - 不是这样。添加了我如何启动作业的代码 sn-p。
  • @trailmax 查看我帖子的更新。希望这能解决您的问题
  • 感谢您的建议,我之前尝试过,但没有任何区别(刚刚再次尝试,没有任何变化:-/)。此外,据我在 Hangfire 的源代码中所见,该过滤器现在是 included by default 并且在调试中检查 GlobalJobFilters.Filters 时确实包含它。
  • @trailmax 我认为这可能是一个错误,但请在调试中尝试。执行三个语句中的每一个,然后查看每个语句的 parentId。不知何故,似乎错误的 parentId 将进入第三条语句
  • 我已经将ContinuationsSupportAttribute复制到我的项目中并单步执行,结果Continuation数据没有添加到父作业中,所以一旦它是Succeeded,它就没有任何触发任何延续的信息。我试图弄清楚为什么没有添加这些数据。
【解决方案2】:

在调查过程中,我们发现我们正在用我们自己的集合替换JobFilterProviderCollection

    var filterProviderCollection = new JobFilterProviderCollection
    {
        new MyFilterProvider(...)
    };
    var backgroundJobClient = new BackgroundJobClient(JobStorage.Current, filterProviderCollection);

MyFilterProvider 看起来像这样:

    public IEnumerable<JobFilter> GetFilters(Job job)
    {
        return new JobFilter[]
        {
             new JobFilter(new HangfireTenantFilter(_tenantDetail, _principal), JobFilterScope.Global,  null),
             new JobFilter(new HangfireFunctionalityFilter(_functionalityFilter), JobFilterScope.Global, null),
        };
    }

事实证明,在 Continuation 上工作的代码只从这个过滤器集合中获取过滤器,ContinuationsSupportAttribute 没有在正确的时间在那里执行。因此,从GlobalJobFilters.Filters 重新添加默认的 Hangfire 过滤器修复了这种情况:

    public IEnumerable<JobFilter> GetFilters(Job job)
    {
        var customFilters = new List<JobFilter>()
        {
             new JobFilter(new HangfireTenantFilter(_tenantDetail, _principal), JobFilterScope.Global,  null),
             new JobFilter(new HangfireFunctionalityFilter(_functionalityFilter), JobFilterScope.Global, null),
        };
        customFilters.AddRange(GlobalJobFilters.Filters);

        return customFilters;
    }

【讨论】:

  • 很高兴你把它整理好了。
  • @Jawad 感谢您抽出宝贵时间回复,不胜感激!享受赏金:-)
  • 谢谢。我有一个类似的问题。我有一个过滤器,我用自己的过滤器返回了一个新的 JobFilter 数组。我猜当时缺少 ContinuationFilter 并且没有执行任何延续。现在我创建一个全局过滤器列表的副本,添加我自己的过滤器并返回整个集合。再次感谢。这是救命稻草。
猜你喜欢
  • 2020-01-23
  • 2021-01-25
  • 2019-05-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-02-20
  • 2015-04-15
相关资源
最近更新 更多