Fix issue with SqlMainDomLock that cannot use implicit lock timeouts … (#9973)

This commit is contained in:
Bjarke Berg
2021-03-12 09:23:32 +01:00
committed by GitHub
parent 8cd41ab36a
commit da5351dfcf
2 changed files with 34 additions and 21 deletions

View File

@@ -409,26 +409,34 @@ namespace Umbraco.Core.Configuration
{
if (_sqlWriteLockTimeOut != default) return _sqlWriteLockTimeOut;
var timeOut = 5000; // 5 seconds
var appSettingSqlWriteLockTimeOut = ConfigurationManager.AppSettings[Constants.AppSettings.SqlWriteLockTimeOut];
if(int.TryParse(appSettingSqlWriteLockTimeOut, out var configuredTimeOut))
{
// Only apply this setting if it's not excessively high or low
const int minimumTimeOut = 100;
const int maximumTimeOut = 20000;
if (configuredTimeOut >= minimumTimeOut && configuredTimeOut <= maximumTimeOut) // between 0.1 and 20 seconds
{
timeOut = configuredTimeOut;
}
else
{
Current.Logger.Warn<GlobalSettings>($"The `{Constants.AppSettings.SqlWriteLockTimeOut}` setting in web.config is not between the minimum of {minimumTimeOut} ms and maximum of {maximumTimeOut} ms, defaulting back to {timeOut}");
}
}
var timeOut = GetSqlWriteLockTimeoutFromConfigFile(Current.Logger);
_sqlWriteLockTimeOut = timeOut;
return _sqlWriteLockTimeOut;
}
}
internal static int GetSqlWriteLockTimeoutFromConfigFile(ILogger logger)
{
var timeOut = 5000; // 5 seconds
var appSettingSqlWriteLockTimeOut = ConfigurationManager.AppSettings[Constants.AppSettings.SqlWriteLockTimeOut];
if (int.TryParse(appSettingSqlWriteLockTimeOut, out var configuredTimeOut))
{
// Only apply this setting if it's not excessively high or low
const int minimumTimeOut = 100;
const int maximumTimeOut = 20000;
if (configuredTimeOut >= minimumTimeOut && configuredTimeOut <= maximumTimeOut) // between 0.1 and 20 seconds
{
timeOut = configuredTimeOut;
}
else
{
logger.Warn<GlobalSettings>(
$"The `{Constants.AppSettings.SqlWriteLockTimeOut}` setting in web.config is not between the minimum of {minimumTimeOut} ms and maximum of {maximumTimeOut} ms, defaulting back to {timeOut}");
}
}
return timeOut;
}
}
}

View File

@@ -1,5 +1,6 @@
using NPoco;
using System;
using System.Configuration;
using System.Data;
using System.Data.SqlClient;
using System.Diagnostics;
@@ -7,6 +8,7 @@ using System.Linq;
using System.Security.Cryptography;
using System.Threading;
using System.Threading.Tasks;
using Umbraco.Core.Configuration;
using Umbraco.Core.Logging;
using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence.Dtos;
@@ -18,6 +20,7 @@ namespace Umbraco.Core.Runtime
{
internal class SqlMainDomLock : IMainDomLock
{
private readonly TimeSpan _lockTimeout;
private string _lockId;
private const string MainDomKeyPrefix = "Umbraco.Core.Runtime.SqlMainDom";
private const string UpdatedSuffix = "_updated";
@@ -40,6 +43,8 @@ namespace Umbraco.Core.Runtime
Constants.System.UmbracoConnectionName,
_logger,
new Lazy<IMapperCollection>(() => new MapperCollection(Enumerable.Empty<BaseMapper>())));
_lockTimeout = TimeSpan.FromMilliseconds(GlobalSettings.GetSqlWriteLockTimeoutFromConfigFile(logger));
}
public async Task<bool> AcquireLockAsync(int millisecondsTimeout)
@@ -198,7 +203,7 @@ namespace Umbraco.Core.Runtime
db.BeginTransaction(IsolationLevel.ReadCommitted);
// get a read lock
_sqlServerSyntax.ReadLock(db, Constants.Locks.MainDom);
_sqlServerSyntax.ReadLock(db, _lockTimeout, Constants.Locks.MainDom);
if (!IsMainDomValue(_lockId, db))
{
@@ -284,7 +289,7 @@ namespace Umbraco.Core.Runtime
{
transaction = db.GetTransaction(IsolationLevel.ReadCommitted);
// get a read lock
_sqlServerSyntax.ReadLock(db, Constants.Locks.MainDom);
_sqlServerSyntax.ReadLock(db, _lockTimeout, Constants.Locks.MainDom);
// the row
var mainDomRows = db.Fetch<KeyValueDto>("SELECT * FROM umbracoKeyValue WHERE [key] = @key", new { key = MainDomKey });
@@ -296,7 +301,7 @@ namespace Umbraco.Core.Runtime
// which indicates that we
// can acquire it and it has shutdown.
_sqlServerSyntax.WriteLock(db, Constants.Locks.MainDom);
_sqlServerSyntax.WriteLock(db, _lockTimeout, Constants.Locks.MainDom);
// so now we update the row with our appdomain id
InsertLockRecord(_lockId, db);
@@ -355,7 +360,7 @@ namespace Umbraco.Core.Runtime
{
transaction = db.GetTransaction(IsolationLevel.ReadCommitted);
_sqlServerSyntax.WriteLock(db, Constants.Locks.MainDom);
_sqlServerSyntax.WriteLock(db, _lockTimeout, Constants.Locks.MainDom);
// so now we update the row with our appdomain id
InsertLockRecord(_lockId, db);
@@ -438,7 +443,7 @@ namespace Umbraco.Core.Runtime
db.BeginTransaction(IsolationLevel.ReadCommitted);
// get a write lock
_sqlServerSyntax.WriteLock(db, Constants.Locks.MainDom);
_sqlServerSyntax.WriteLock(db, _lockTimeout, Constants.Locks.MainDom);
// When we are disposed, it means we have released the MainDom lock
// and called all MainDom release callbacks, in this case