从服务器不应该监听的队列中获取作业

问题描述 投票:0回答:1

我发现了几个听起来相似但从未真正解决的问题。

我有两台 Hangfire 服务器。我们称它们为 A 和 B。服务器 A 配置为侦听 QueueA(并且只有 QueueA,没有“默认”队列!),服务器 B 侦听 QueueB(也没有“默认”队列)。我有一项安排在 QueueA 上的作业(无论我将其安排为后台作业还是重复作业都没有关系)。但该工作(有时)会由服务器 B 接手。

services.AddHangfireServer((sp, options) =>
{
    options.Queues = new[] { "queue_a" };
    options.WorkerCount = 1;
    options.ServerName = "server-a";
});


services.AddHangfireServer((sp, options) =>
{
    options.Queues = new[] { "queue_b" };
    options.WorkerCount = 1;
    options.ServerName = "server-b";
});

recurringJobManager.AddOrUpdate<JobA>(
                    nameof(JobA),
                    "queue_a",
                    job => job.Execute(CancellationToken.None),
                    "<some cron expression>");

问题:服务器 B 没有引用同一组程序集,因此甚至无法从数据库加载作业。服务器 B 不会让其他服务器接收它,而是继续尝试,直到重试次数用尽并且作业失败。

Hangfire.Common.JobLoadException: Could not load the job. See inner exception for the details.
 ---> System.IO.FileNotFoundException: Could not resolve assembly 'JobA'.
   at System.Reflection.TypeNameParser.ResolveAssembly(String assemblyName)
   at System.Reflection.TypeNameParser.GetType(String typeName, ReadOnlySpan`1 nestedTypeNames, String assemblyNameIfAny)
   at System.Reflection.TypeNameParser.NamespaceTypeName.ResolveType(TypeNameParser& parser, String containingAssemblyIfAny)
   at System.Reflection.TypeNameParser.Parse()
   at System.Reflection.TypeNameParser.GetType(String typeName, Func`2 assemblyResolver, Func`4 typeResolver, Assembly requestingAssembly, Boolean throwOnError, Boolean ignoreCase, Boolean extensibleParser)
   at System.Type.GetType(String typeName, Func`2 assemblyResolver, Func`4 typeResolver, Boolean throwOnError)
   at Hangfire.Common.TypeHelper.DefaultTypeResolver(String typeName) in C:\projects\hangfire-525\src\Hangfire.Core\Common\TypeHelper.cs:line 78
   at Hangfire.Storage.InvocationData.DeserializeJob() in C:\projects\hangfire-525\src\Hangfire.Core\Storage\InvocationData.cs:line 96
   --- End of inner exception stack trace ---
   at Hangfire.Storage.InvocationData.DeserializeJob() in C:\projects\hangfire-525\src\Hangfire.Core\Storage\InvocationData.cs:line 120
   at Hangfire.RecurringJobExtensions.TriggerRecurringJob(IBackgroundJobFactory factory, JobStorage storage, IStorageConnection connection, IProfiler profiler, RecurringJobEntity recurringJob, DateTime now) in C:\projects\hangfire-525\src\Hangfire.Core\RecurringJobExtensions.cs:line 115
   at Hangfire.Server.RecurringJobScheduler.ScheduleRecurringJob(BackgroundProcessContext context, IStorageConnection connection, String recurringJobId, RecurringJobEntity recurringJob, DateTime now) in C:\projects\hangfire-525\src\Hangfire.Core\Server\RecurringJobScheduler.cs:line 333

我有一个作业过滤器,可以确保使用原始队列,即使在重试时也是如此。因此,该问题与使用错误队列重新排队的作业无关。

为什么服务器会从队列中获取作业,而它不应该监听,我该如何解决这个问题?

顺便说一句:此问题与使用的存储无关。我在 SqlServer、Redis 和 PostgreSql 中看到了它。

hangfire
1个回答
0
投票

我联系了 Hangfire 支持人员,他们出色地解决了我的问题!

如果您有像我这样的类似设置(多个重复作业和具有不同引用程序集集的多个服务器),则该问题是已知的,并且 Hangfire 提供了解决方案:DynamicJobs

基本上,您所要做的就是在所有服务器中引用 NuGet 包(扩展方法

.UseDynamicJobs()
)并将安排作业的代码行从
AddOrUpdate
更改为
AddOrUpdateDynamic
。有了这个,我必须稍微扩展我的自定义作业过滤器,因为对于重复作业,队列还不是作业调用数据的一部分。

这解决了重复作业被错误的服务器接收的问题。

对于常规的即发即忘后台作业,一旦我从直接设置状态(通过

new EnqueuedState("queueName")
)切换到使用已经接受
Enqueue<TJob>(...)
作为参数的
queue
重载,问题就消失了。

© www.soinside.com 2019 - 2024. All rights reserved.