Skip to content

Commit de4b3af

Browse files
author
Paul Johnson
authored
Resolve various points related to deficiencies in FileSystemMainDomLock (#12052)
* Resolve various points related to deficiencies in FileSystemMainDomLock See GH #12049 * Increasing backoff time for retry when deleting lock release signal file However reducing max tries, really hoping this never actually happens and if it does, failing to boot ASAP seems reasonable.
1 parent 321d5b4 commit de4b3af

File tree

1 file changed

+32
-16
lines changed

1 file changed

+32
-16
lines changed

src/Umbraco.Infrastructure/Runtime/FileSystemMainDomLock.cs

Lines changed: 32 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using System.Collections.Generic;
23
using System.Diagnostics;
34
using System.IO;
45
using System.Threading;
@@ -11,21 +12,22 @@ namespace Umbraco.Cms.Infrastructure.Runtime
1112
{
1213
internal class FileSystemMainDomLock : IMainDomLock
1314
{
14-
private readonly ILogger<FileSystemMainDomLock> _log;
15-
15+
private readonly ILogger<FileSystemMainDomLock> _logger;
1616
private readonly CancellationTokenSource _cancellationTokenSource = new();
17-
1817
private readonly string _lockFilePath;
1918
private readonly string _releaseSignalFilePath;
2019

2120
private FileStream _lockFileStream;
21+
private Task _listenForReleaseSignalFileTask;
22+
23+
private const int s_maxTriesRemovingLockReleaseSignalFile = 3;
2224

2325
public FileSystemMainDomLock(
24-
ILogger<FileSystemMainDomLock> log,
26+
ILogger<FileSystemMainDomLock> logger,
2527
IMainDomKeyGenerator mainDomKeyGenerator,
2628
IHostingEnvironment hostingEnvironment)
2729
{
28-
_log = log;
30+
_logger = logger;
2931

3032
var lockFileName = $"MainDom_{mainDomKeyGenerator.GenerateKey()}.lock";
3133
_lockFilePath = Path.Combine(hostingEnvironment.LocalTempPath, lockFileName);
@@ -41,20 +43,20 @@ public Task<bool> AcquireLockAsync(int millisecondsTimeout)
4143
{
4244
try
4345
{
44-
_log.LogDebug("Attempting to obtain MainDom lock file handle {lockFilePath}", _lockFilePath);
46+
_logger.LogDebug("Attempting to obtain MainDom lock file handle {lockFilePath}", _lockFilePath);
4547
_lockFileStream = File.Open(_lockFilePath, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None);
4648
DeleteLockReleaseFile();
4749
return Task.FromResult(true);
4850
}
4951
catch (IOException)
5052
{
51-
_log.LogDebug("Couldn't obtain MainDom lock file handle, signalling for release of {lockFilePath}", _lockFilePath);
53+
_logger.LogDebug("Couldn't obtain MainDom lock file handle, signalling for release of {lockFilePath}", _lockFilePath);
5254
CreateLockReleaseFile();
5355
Thread.Sleep(500);
5456
}
5557
catch (Exception ex)
5658
{
57-
_log.LogError(ex, "Unexpected exception attempting to obtain MainDom lock file handle {lockFilePath}, giving up", _lockFilePath);
59+
_logger.LogError(ex, "Unexpected exception attempting to obtain MainDom lock file handle {lockFilePath}, giving up", _lockFilePath);
5860
return Task.FromResult(false);
5961
}
6062
}
@@ -64,13 +66,22 @@ public Task<bool> AcquireLockAsync(int millisecondsTimeout)
6466
}
6567

6668
// Create a long running task to poll to check if anyone has created a lock release file.
67-
public Task ListenAsync() =>
68-
Task.Factory.StartNew(
69+
public Task ListenAsync()
70+
{
71+
if (_listenForReleaseSignalFileTask != null)
72+
{
73+
return _listenForReleaseSignalFileTask;
74+
}
75+
76+
_listenForReleaseSignalFileTask = Task.Factory.StartNew(
6977
ListeningLoop,
7078
_cancellationTokenSource.Token,
7179
TaskCreationOptions.LongRunning,
7280
TaskScheduler.Default);
7381

82+
return _listenForReleaseSignalFileTask;
83+
}
84+
7485
public void Dispose()
7586
{
7687
_lockFileStream?.Close();
@@ -86,24 +97,29 @@ private void CreateLockReleaseFile()
8697
}
8798
catch (Exception ex)
8899
{
89-
_log.LogError(ex, "Unexpected exception attempting to create lock release signal file {file}", _releaseSignalFilePath);
100+
_logger.LogError(ex, "Unexpected exception attempting to create lock release signal file {file}", _releaseSignalFilePath);
90101
}
91102
}
92103

93104
private void DeleteLockReleaseFile()
94105
{
95-
while (File.Exists(_releaseSignalFilePath))
106+
List<Exception> encounteredExceptions = new();
107+
for (var i = 0; i < s_maxTriesRemovingLockReleaseSignalFile; i++)
96108
{
97109
try
98110
{
99111
File.Delete(_releaseSignalFilePath);
112+
return;
100113
}
101114
catch (Exception ex)
102115
{
103-
_log.LogError(ex, "Unexpected exception attempting to delete release signal file {file}", _releaseSignalFilePath);
104-
Thread.Sleep(500);
116+
_logger.LogError(ex, "Unexpected exception attempting to delete release signal file {file}", _releaseSignalFilePath);
117+
encounteredExceptions.Add(ex);
118+
Thread.Sleep(500 * (i + 1));
105119
}
106120
}
121+
122+
throw new ApplicationException($"Failed to remove lock release signal file {_releaseSignalFilePath}", new AggregateException(encounteredExceptions));
107123
}
108124

109125
private void ListeningLoop()
@@ -112,13 +128,13 @@ private void ListeningLoop()
112128
{
113129
if (_cancellationTokenSource.IsCancellationRequested)
114130
{
115-
_log.LogDebug("ListenAsync Task canceled, exiting loop");
131+
_logger.LogDebug("ListenAsync Task canceled, exiting loop");
116132
return;
117133
}
118134

119135
if (File.Exists(_releaseSignalFilePath))
120136
{
121-
_log.LogDebug("Found lock release signal file, releasing lock on {lockFilePath}", _lockFilePath);
137+
_logger.LogDebug("Found lock release signal file, releasing lock on {lockFilePath}", _lockFilePath);
122138
_lockFileStream?.Close();
123139
_lockFileStream = null;
124140
break;

0 commit comments

Comments
 (0)