Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/21.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Asp.net 为什么Hangfire在轮询sql server查找作业时每隔几秒钟等待15秒?_Asp.net_.net_Hangfire - Fatal编程技术网

Asp.net 为什么Hangfire在轮询sql server查找作业时每隔几秒钟等待15秒?

Asp.net 为什么Hangfire在轮询sql server查找作业时每隔几秒钟等待15秒?,asp.net,.net,hangfire,Asp.net,.net,Hangfire,我继承了一个使用Hangfire和sql server作业存储的系统。通常,当计划立即运行作业时,我们会注意到它需要几秒钟才能触发 在我的开发环境中运行SQL Profiler时,针对Hangfire db运行的SQL如下所示- exec sp_executesql N'delete top (1) JQ output DELETED.Id, DELETED.JobId, DELETED.Queue from [HangFire].JobQueue JQ with (readpast, updl

我继承了一个使用Hangfire和sql server作业存储的系统。通常,当计划立即运行作业时,我们会注意到它需要几秒钟才能触发

在我的开发环境中运行SQL Profiler时,针对Hangfire db运行的SQL如下所示-

exec sp_executesql N'delete top (1) JQ
output DELETED.Id, DELETED.JobId, DELETED.Queue
from [HangFire].JobQueue JQ with (readpast, updlock, rowlock, forceseek)
where 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

-- Exactly the same SQL as above is executed about 6 times/second for about 3-4 seconds,
-- then nothing for about 2 seconds, then: 

exec sp_getapplock @Resource=N'HangFire:recurring-jobs:lock',@DbPrincipal=N'public',@LockMode=N'Exclusive',@LockOwner=N'Session',@LockTimeout=5000
exec sp_getapplock @Resource=N'HangFire:locks:schedulepoller',@DbPrincipal=N'public',@LockMode=N'Exclusive',@LockOwner=N'Session',@LockTimeout=5000
exec 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
exec 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
exec sp_releaseapplock @Resource=N'HangFire:recurring-jobs:lock',@LockOwner=N'Session'
exec sp_releaseapplock @Resource=N'HangFire:locks:schedulepoller',@LockOwner=N'Session'

-- Then nothing is executed for about 8-10 seconds, then: 

exec 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'

-- Then about 500ms-2s later I get 
exec sp_executesql N'delete top (1) JQ ... -- i.e. Same as first query
The update LastHeartbeat query is only there every second time (from just a brief inspection, maybe that’s not exactly right).
但如果说有什么问题的话,现在的问题更糟了。或者相同但更快:20次调用
delete top(1)JQ…
现在大约在1s内发生,然后是其他查询,然后是15秒等待,然后又重新开始

需要明确的是,主要的问题是,如果在15秒延迟期间添加了任何作业,那么在我的作业执行之前,需要15秒的剩余时间。我认为第二个问题是,它对SQL Server的影响超出了需要:一秒钟20次有点大,至少对我的需要来说是这样


(交叉发布到)

我建议查看Hangfire
BackgroundJobServerOptions
查看您在那里设置的轮询间隔。这将定义hangfire服务器检查队列中是否有要执行的作业之前的时间

来自文档

Hangfire Server会定期检查计划,将计划的作业排入其队列,从而允许工作人员 执行它们。默认情况下,检查间隔等于15秒,但您可以通过在传递给BackgroundJobServer构造函数的选项上设置SchedulePollingInterval属性来更改它:


如果未设置
QueuePollInterval
,则使用sql server存储的Hangfire默认为每15秒轮询一次。因此,如果出现此问题,首先要将
QueuePollInterval
设置为较小的值,例如1s

但在我的情况下,即使我设定它没有任何效果。原因是在调用
app.UseHangfireServer()
之前,我使用
SqlServerStorageOptions
调用了
GlobalConfiguration.Configuration.UseSqlServerStorage()

调用
app.UseHangfireServer()
时,它使用
JobStorage.current的当前值。我的代码设置为:

    var storage = new SqlServerStorage(connstring);
    JobStorage.Current = storage;
后来打电话来

    app.UseHangfireServer()
        GlobalConfiguration.Configuration
            .UseSqlServerStorage(connstring, new SqlServerStorageOptions
        {
            CommandBatchMaxTimeout = TimeSpan.FromMinutes(5),
            QueuePollInterval = TimeSpan.Zero,
            SlidingInvisibilityTimeout = TimeSpan.FromMinutes(5),
            UseRecommendedIsolationLevel = true,
            PrepareSchemaIfNecessary = true, 
            EnableHeavyMigrations = true     
        })
后来打电话来

    app.UseHangfireServer()
        GlobalConfiguration.Configuration
            .UseSqlServerStorage(connstring, new SqlServerStorageOptions
        {
            CommandBatchMaxTimeout = TimeSpan.FromMinutes(5),
            QueuePollInterval = TimeSpan.Zero,
            SlidingInvisibilityTimeout = TimeSpan.FromMinutes(5),
            UseRecommendedIsolationLevel = true,
            PrepareSchemaIfNecessary = true, 
            EnableHeavyMigrations = true     
        })

将其重新排序以在
app之前使用
SqlServerStorageOptions
。UseHangfireServer()
意味着
SqlServerStorageOptions
生效。

感谢您的指针,但my
BackgroundJobServerOptions
仅设置了
队列
属性。我不太明白投票间隔是用来做什么的,所以我会去仔细阅读。好了,现在我明白了。不,在这种情况下,我们通常会触发立即运行作业,因此您所说的15秒轮询不应该相关,因为这是为了将作业添加到应该很快运行的队列中,例如,如果它们是像
BackgroundJob.Schedule(()=>Console.WriteLine(“Hello,world”)、TimeSpan.FromDays(1)这样创建的您可以运行BackgroundJob.Schedule或BackgroundJob.Enqueue。。。两者使用相同的轮询间隔。一定要测试一下,看看这对你的处境是否有帮助。BackgroundJobServeroptions中的大多数值都设置为默认值,但您可以将这些值覆盖为默认值以外的值(
new TimeSpan(0,0,5)
5秒间隔,然后Hangfire服务器拾取下一个作业)。谢谢,我将详细介绍。但总的来说,您不希望Hangfire不断地轮询sqlserver以获得新的工作吗?我是说,为什么它会停止投票?这是在没有作业可执行的情况下。。。因此,当我们添加一份工作时,在开始之前会有一个很大的停顿,因为Hangfire没有持续进行投票。我之所以授予奖金,是因为你的回答为我指明了正确的方向,尽管没有直接解决问题。我将发布一个答案来解释更多。根据来源中的这一行,将QueuePollInterval设置为0会使系统切换到长轮询。我建议选择一个严格高于1s的值,比如2s,来改变等待策略,看看它是否有区别(除了删除转换为更新)。谢谢,我会尝试一下。仍然无法解释为什么它会经常等待10秒,很明显,无论它使用什么策略,这都是不好的。但也许战略的改变意味着它无论如何都会停止这样做。