Hangfire ContinueWithJob 卡在等待状态,尽管父作业已经成功
Hangfire ContinueWithJob is stuck in awaiting state, though parent job has succeeded
我通过 ContinueJobWith<MyHandler>(parentJobId, x => x.DoWork())
一个接一个地执行了一些作业。
但是,第二个作业没有得到处理,始终处于 Awaiting
状态:
作业本身是这样的:
为什么会发生这种情况以及在哪里检查结果?
- 我们使用 Autofac 作为 DI 容器,但我们有自己的
JobActivator
实现,因为我们必须处理多租户。
- 我们正在使用 SQL Server 2019 进行存储。
- Hangfire 版本为 1.7.10
- 这是 MVC 5 应用程序
- 我在任何日志或调试期间都没有看到任何 errors/exceptions
- 完成 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()));
所有参数都是int
、bool
或string
。如果我手动将等待的作业排入队列,它们将毫无问题地执行。
我添加了 Hangfire 日志记录,但看不到任何问题:服务器启动、停止、作业更改状态,但看不到任何明显的错误。
我还应该考虑哪些其他事项或 where/how 我应该对此进行调试?
从表面上看,ID 为 216348
的第一个作业已成功完成,但 ID 为 216349
的第二个作业正在等待 216347
的父 ID。根据 Hangfire 文档和经验,parentID 应该是您在执行第二个作业之前等待完成的作业。
根据 Hangfire documentation on ContinueJobWith,“在其父作业 完成后执行继续 ”。从您的屏幕截图中,不清楚 JobID 是怎么回事:216347
。此作业 216347
完成后,ID 为 216349
的作业应启动。如果您希望 216349
在 216348
完成后开始,请检查您的代码并确保将正确的 ParentID 传递给第二个作业。
Update
基于on this thread,将ContinuationsSupportAttribute
添加到配置Hangfire 服务的GlobalJobFilters.Filter
。这应该使您的 Hangfire 实例知道继续作业。
GlobalJobFilters.Filters.Add(new ContinuationsSupportAttribute());
在调查过程中,发现我们将 JobFilterProviderCollection
替换为我们自己的 collection:
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 上工作的代码只从这个过滤器 collection 中获取过滤器,ContinuationsSupportAttribute
没有在正确的时间在那里执行。因此 re-adding 来自 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;
}
我通过 ContinueJobWith<MyHandler>(parentJobId, x => x.DoWork())
一个接一个地执行了一些作业。
但是,第二个作业没有得到处理,始终处于 Awaiting
状态:
作业本身是这样的:
为什么会发生这种情况以及在哪里检查结果?
- 我们使用 Autofac 作为 DI 容器,但我们有自己的
JobActivator
实现,因为我们必须处理多租户。 - 我们正在使用 SQL Server 2019 进行存储。
- Hangfire 版本为 1.7.10
- 这是 MVC 5 应用程序
- 我在任何日志或调试期间都没有看到任何 errors/exceptions
- 完成 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()));
所有参数都是int
、bool
或string
。如果我手动将等待的作业排入队列,它们将毫无问题地执行。
我添加了 Hangfire 日志记录,但看不到任何问题:服务器启动、停止、作业更改状态,但看不到任何明显的错误。
我还应该考虑哪些其他事项或 where/how 我应该对此进行调试?
从表面上看,ID 为 216348
的第一个作业已成功完成,但 ID 为 216349
的第二个作业正在等待 216347
的父 ID。根据 Hangfire 文档和经验,parentID 应该是您在执行第二个作业之前等待完成的作业。
根据 Hangfire documentation on ContinueJobWith,“在其父作业 完成后执行继续 ”。从您的屏幕截图中,不清楚 JobID 是怎么回事:216347
。此作业 216347
完成后,ID 为 216349
的作业应启动。如果您希望 216349
在 216348
完成后开始,请检查您的代码并确保将正确的 ParentID 传递给第二个作业。
Update
基于on this thread,将ContinuationsSupportAttribute
添加到配置Hangfire 服务的GlobalJobFilters.Filter
。这应该使您的 Hangfire 实例知道继续作业。
GlobalJobFilters.Filters.Add(new ContinuationsSupportAttribute());
在调查过程中,发现我们将 JobFilterProviderCollection
替换为我们自己的 collection:
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 上工作的代码只从这个过滤器 collection 中获取过滤器,ContinuationsSupportAttribute
没有在正确的时间在那里执行。因此 re-adding 来自 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;
}