From c61b70d116ece1d2c7b132a88f70103f8ed7e09d Mon Sep 17 00:00:00 2001 From: isafar Date: Tue, 10 Sep 2019 16:41:38 +0200 Subject: [PATCH 1/2] I found that the most resource hogger for our sql server is the sp_getapplock. This server is a huge report server with many data load (importing data from the cloud), and we get the the most wait time is sp_getapplock. I would recommend a new option and we can dequeue jobs without applock. WITH (ROWLOCK) for update should be enough --- src/Hangfire.SqlServer/SqlServerJobQueue.cs | 2 +- src/Hangfire.SqlServer/SqlServerStorageOptions.cs | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Hangfire.SqlServer/SqlServerJobQueue.cs b/src/Hangfire.SqlServer/SqlServerJobQueue.cs index 7b261652b..466ab03fa 100644 --- a/src/Hangfire.SqlServer/SqlServerJobQueue.cs +++ b/src/Hangfire.SqlServer/SqlServerJobQueue.cs @@ -90,7 +90,7 @@ private SqlServerTimeoutJob DequeueUsingSlidingInvisibilityTimeout(string[] queu if (queues.Length == 0) throw new ArgumentException("Queue array must be non-empty.", nameof(queues)); var lockResource = $"{_storage.SchemaName}_FetchLockLock_{String.Join("_", queues.OrderBy(x => x))}"; - var isBlocking = false; + var isBlocking = _options.NonBlockingFetchSql; var pollingDelayMs = Math.Min( Math.Max((int)_options.QueuePollInterval.TotalMilliseconds, MinPollingDelayMs), diff --git a/src/Hangfire.SqlServer/SqlServerStorageOptions.cs b/src/Hangfire.SqlServer/SqlServerStorageOptions.cs index c3229feba..cce5ebf3f 100644 --- a/src/Hangfire.SqlServer/SqlServerStorageOptions.cs +++ b/src/Hangfire.SqlServer/SqlServerStorageOptions.cs @@ -45,6 +45,7 @@ public SqlServerStorageOptions() TransactionTimeout = TimeSpan.FromMinutes(1); DisableGlobalLocks = false; UsePageLocksOnDequeue = false; + NonBlockingFetchSql = true; } [Obsolete("TransactionIsolationLevel option is deprecated, please set UseRecommendedIsolationLevel instead. Will be removed in 2.0.0.")] @@ -122,5 +123,7 @@ public string SchemaName public bool UsePageLocksOnDequeue { get; set; } public bool UseRecommendedIsolationLevel { get; set; } public bool EnableHeavyMigrations { get; set; } + + public bool NonBlockingFetchSql { get; set; } } } From a21b12f12e27db82ccf885ad810064bcba6a4767 Mon Sep 17 00:00:00 2001 From: isafar Date: Thu, 12 Sep 2019 08:45:29 +0200 Subject: [PATCH 2/2] NonBlockingFetchSql override _options.QueuePollInterval < LongPollingThreshold --- src/Hangfire.SqlServer/SqlServerJobQueue.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Hangfire.SqlServer/SqlServerJobQueue.cs b/src/Hangfire.SqlServer/SqlServerJobQueue.cs index 466ab03fa..c6608887f 100644 --- a/src/Hangfire.SqlServer/SqlServerJobQueue.cs +++ b/src/Hangfire.SqlServer/SqlServerJobQueue.cs @@ -144,7 +144,7 @@ private SqlServerTimeoutJob DequeueUsingSlidingInvisibilityTimeout(string[] queu throw new InvalidOperationException($"A call to sp_getapplock returned unexpected result '{lockResult.Value}' while fetching a job. Please report this problem to Hangfire developers and don't use sub-second values for the QueuePollInterval option."); } - if (_options.QueuePollInterval < LongPollingThreshold) + if (_options.QueuePollInterval < LongPollingThreshold && !_options.NonBlockingFetchSql) { isBlocking = true; }