Ror*_*ory 0 .net asp.net hangfire
我\xe2\x80\x99继承了一个使用Hangfire和sql server作业存储的系统。通常,当计划立即运行作业时,我们会注意到它需要几秒钟的时间才能触发\xe2\x80\x99s。
\n在我的开发环境中运行时查看 SQL Profiler,针对 Hangfire 数据库运行的 SQL 如下所示 -
\nexec sp_executesql N\'delete top (1) JQ\noutput DELETED.Id, DELETED.JobId, DELETED.Queue\nfrom [HangFire].JobQueue JQ with (readpast, updlock, rowlock, forceseek)\nwhere Queue in (@queues1) and (FetchedAt is null or FetchedAt < DATEADD(second, @timeout, GETUTCDATE()))\',N\'@queues1 nvarchar(4000),@timeout float\',@queues1=N\'MYQUEUENAME_master\',@timeout=-1800\n\n-- Exactly the same SQL as above is executed about 6 times/second for about 3-4 seconds,\n-- then nothing for about 2 seconds, then: \n\nexec sp_getapplock @Resource=N\'HangFire:recurring-jobs:lock\',@DbPrincipal=N\'public\',@LockMode=N\'Exclusive\',@LockOwner=N\'Session\',@LockTimeout=5000\nexec sp_getapplock @Resource=N\'HangFire:locks:schedulepoller\',@DbPrincipal=N\'public\',@LockMode=N\'Exclusive\',@LockOwner=N\'Session\',@LockTimeout=5000\nexec sp_executesql N\'select top (@count) Value from [HangFire].[Set] with (readcommittedlock, forceseek) where [Key] = @key and Score between @from and @to order by Score\',N\'@count int,@key nvarchar(4000),@from float,@to float\',@count=1000,@key=N\'recurring-jobs\',@from=0,@to=1596053348\nexec sp_executesql N\'select top (@count) Value from [HangFire].[Set] with (readcommittedlock, forceseek) where [Key] = @key and Score between @from and @to order by Score\',N\'@count int,@key nvarchar(4000),@from float,@to float\',@count=1000,@key=N\'schedule\',@from=0,@to=1596053348\nexec sp_releaseapplock @Resource=N\'HangFire:recurring-jobs:lock\',@LockOwner=N\'Session\'\nexec sp_releaseapplock @Resource=N\'HangFire:locks:schedulepoller\',@LockOwner=N\'Session\'\n\n-- Then nothing is executed for about 8-10 seconds, then: \n\nexec sp_executesql N\'update [HangFire].Server set LastHeartbeat = @now where Id = @id\',N\'@now datetime,@id nvarchar(4000)\',@now=\'2020-07-29 20:09:19.097\',@id=N\'ps12345:19764:fe362d1a-5ee4-4d97-b70d-134fdfab2b87\'\n\n-- Then about 500ms-2s later I get \nexec sp_executesql N\'delete top (1) JQ ... -- i.e. Same as first query\nThe update LastHeartbeat query is only there every second time (from just a brief inspection, maybe that\xe2\x80\x99s not exactly right).\nRun Code Online (Sandbox Code Playgroud)\n看起来 \xe2\x80\x99 至少有 3 个线程对 JQ 运行 DELETE 查询,因为我可以看到几个 RPC:Starting 在 RPC:Completed 之前,表明它们 \xe2\x80\x99 正在并行执行而不是顺序执行\n我不知道 \xe2\x80\x99 是否正常,但看起来很奇怪,因为我认为我们只有一个 \xe2\x80\x98consumer\xe2\x80\x99 的工作。
\n我的开发环境中只有一个队列,尽管在实际情况下我们\xe2\x80\x99d 有 20-50 个 I\xe2\x80\x99d 猜测。
\n关于我应该在哪里查找导致\xe2\x80\x99s 的配置的任何建议:\na) 检查作业之间的 8-10 秒暂停\nb) 正在检查作业的线程数 - 似乎我也有许多
\n写完这篇文章后,我意识到我们使用的是旧版本,因此我从 1.5.x 升级到 1.7.12,升级了数据库,并将启动配置更改为:
\n app.UseHangfireDashboard();\n\n GlobalConfiguration.Configuration\n .UseSqlServerStorage(connstring, new SqlServerStorageOptions\n {\n CommandBatchMaxTimeout = TimeSpan.FromMinutes(5),\n QueuePollInterval = TimeSpan.Zero,\n SlidingInvisibilityTimeout = TimeSpan.FromMinutes(5),\n UseRecommendedIsolationLevel = true,\n PrepareSchemaIfNecessary = true, // Default value: true\n EnableHeavyMigrations = true // Default value: false\n })\n .UseAutofacActivator(_container);\n JobActivator.Current = new AutofacJobActivator(_container);\nRun Code Online (Sandbox Code Playgroud)\n但如果说有什么不同的话,那就是现在的问题更加严重了。或者相同但更快:delete top (1) JQ...现在大约 1 秒内发生 20 个调用,然后是其他查询,然后等待 15 秒,然后重新开始。
需要明确的是,主要问题是,如果在这 15 秒的延迟期间添加了任何作业,那么将需要这 15 秒的剩余时间才能执行我的作业。我认为第二个问题是它对 SQL Server 的影响超出了需要:每秒 20 次有点太多了,至少对于我的需要来说。
\n(交叉发布到hangfire 论坛)
\n如果您未设置,QueuePollInterval则带有 sql server 存储的 Hangfire 默认每 15 秒轮询一次。因此,如果遇到此问题,首先要做的就是设置QueuePollInterval较小的值,例如 1s。
但就我而言,即使我设置了它也没有任何效果。原因是在我打电话之前app.UseHangfireServer() 就打电话了。GlobalConfiguration.Configuration.UseSqlServerStorage()SqlServerStorageOptions
当您调用时,app.UseHangfireServer()它使用 的当前值JobStorage.Current。我的代码已设置:
var storage = new SqlServerStorage(connstring);
JobStorage.Current = storage;
Run Code Online (Sandbox Code Playgroud)
然后后来打电话
app.UseHangfireServer()
Run Code Online (Sandbox Code Playgroud)
然后后来打电话
GlobalConfiguration.Configuration
.UseSqlServerStorage(connstring, new SqlServerStorageOptions
{
CommandBatchMaxTimeout = TimeSpan.FromMinutes(5),
QueuePollInterval = TimeSpan.Zero,
SlidingInvisibilityTimeout = TimeSpan.FromMinutes(5),
UseRecommendedIsolationLevel = true,
PrepareSchemaIfNecessary = true,
EnableHeavyMigrations = true
})
Run Code Online (Sandbox Code Playgroud)
重新排序为SqlServerStorageOptions之前使用app.UseHangfireServer()即SqlServerStorageOptions生效。