1
1
using System ;
2
- using System . Collections . Generic ;
3
2
using System . Diagnostics ;
4
3
using System . IO ;
5
4
using System . Threading ;
6
5
using System . Threading . Tasks ;
7
6
using Microsoft . Extensions . Logging ;
7
+ using Microsoft . Extensions . Options ;
8
+ using Umbraco . Cms . Core . Configuration . Models ;
8
9
using Umbraco . Cms . Core . Hosting ;
9
10
using Umbraco . Cms . Core . Runtime ;
10
11
@@ -13,21 +14,22 @@ namespace Umbraco.Cms.Infrastructure.Runtime
13
14
internal class FileSystemMainDomLock : IMainDomLock
14
15
{
15
16
private readonly ILogger < FileSystemMainDomLock > _logger ;
17
+ private readonly IOptionsMonitor < GlobalSettings > _globalSettings ;
16
18
private readonly CancellationTokenSource _cancellationTokenSource = new ( ) ;
17
19
private readonly string _lockFilePath ;
18
20
private readonly string _releaseSignalFilePath ;
19
21
20
22
private FileStream _lockFileStream ;
21
23
private Task _listenForReleaseSignalFileTask ;
22
24
23
- private const int s_maxTriesRemovingLockReleaseSignalFile = 3 ;
24
-
25
25
public FileSystemMainDomLock (
26
26
ILogger < FileSystemMainDomLock > logger ,
27
27
IMainDomKeyGenerator mainDomKeyGenerator ,
28
- IHostingEnvironment hostingEnvironment )
28
+ IHostingEnvironment hostingEnvironment ,
29
+ IOptionsMonitor < GlobalSettings > globalSettings )
29
30
{
30
31
_logger = logger ;
32
+ _globalSettings = globalSettings ;
31
33
32
34
var lockFileName = $ "MainDom_{ mainDomKeyGenerator . GenerateKey ( ) } .lock";
33
35
_lockFilePath = Path . Combine ( hostingEnvironment . LocalTempPath , lockFileName ) ;
@@ -45,18 +47,18 @@ public Task<bool> AcquireLockAsync(int millisecondsTimeout)
45
47
{
46
48
_logger . LogDebug ( "Attempting to obtain MainDom lock file handle {lockFilePath}" , _lockFilePath ) ;
47
49
_lockFileStream = File . Open ( _lockFilePath , FileMode . OpenOrCreate , FileAccess . ReadWrite , FileShare . None ) ;
48
- DeleteLockReleaseFile ( ) ;
50
+ DeleteLockReleaseSignalFile ( ) ;
49
51
return Task . FromResult ( true ) ;
50
52
}
51
53
catch ( IOException )
52
54
{
53
55
_logger . LogDebug ( "Couldn't obtain MainDom lock file handle, signalling for release of {lockFilePath}" , _lockFilePath ) ;
54
- CreateLockReleaseFile ( ) ;
55
- Thread . Sleep ( 500 ) ;
56
+ CreateLockReleaseSignalFile ( ) ;
56
57
}
57
58
catch ( Exception ex )
58
59
{
59
60
_logger . LogError ( ex , "Unexpected exception attempting to obtain MainDom lock file handle {lockFilePath}, giving up" , _lockFilePath ) ;
61
+ _lockFileStream ? . Close ( ) ;
60
62
return Task . FromResult ( false ) ;
61
63
}
62
64
}
@@ -65,6 +67,12 @@ public Task<bool> AcquireLockAsync(int millisecondsTimeout)
65
67
return Task . FromResult ( false ) ;
66
68
}
67
69
70
+ public void CreateLockReleaseSignalFile ( ) =>
71
+ _ = File . Open ( _releaseSignalFilePath , FileMode . OpenOrCreate , FileAccess . ReadWrite , FileShare . ReadWrite | FileShare . Delete ) ;
72
+
73
+ public void DeleteLockReleaseSignalFile ( ) =>
74
+ File . Delete ( _releaseSignalFilePath ) ;
75
+
68
76
// Create a long running task to poll to check if anyone has created a lock release file.
69
77
public Task ListenAsync ( )
70
78
{
@@ -82,46 +90,6 @@ public Task ListenAsync()
82
90
return _listenForReleaseSignalFileTask ;
83
91
}
84
92
85
- public void Dispose ( )
86
- {
87
- _lockFileStream ? . Close ( ) ;
88
- _lockFileStream = null ;
89
- }
90
-
91
- private void CreateLockReleaseFile ( )
92
- {
93
- try
94
- {
95
- // Dispose immediately to release the file handle so it's easier to cleanup in any process.
96
- using FileStream releaseFileStream = File . Open ( _releaseSignalFilePath , FileMode . OpenOrCreate , FileAccess . ReadWrite , FileShare . ReadWrite ) ;
97
- }
98
- catch ( Exception ex )
99
- {
100
- _logger . LogError ( ex , "Unexpected exception attempting to create lock release signal file {file}" , _releaseSignalFilePath ) ;
101
- }
102
- }
103
-
104
- private void DeleteLockReleaseFile ( )
105
- {
106
- List < Exception > encounteredExceptions = new ( ) ;
107
- for ( var i = 0 ; i < s_maxTriesRemovingLockReleaseSignalFile ; i ++ )
108
- {
109
- try
110
- {
111
- File . Delete ( _releaseSignalFilePath ) ;
112
- return ;
113
- }
114
- catch ( Exception ex )
115
- {
116
- _logger . LogError ( ex , "Unexpected exception attempting to delete release signal file {file}" , _releaseSignalFilePath ) ;
117
- encounteredExceptions . Add ( ex ) ;
118
- Thread . Sleep ( 500 * ( i + 1 ) ) ;
119
- }
120
- }
121
-
122
- throw new ApplicationException ( $ "Failed to remove lock release signal file { _releaseSignalFilePath } ", new AggregateException ( encounteredExceptions ) ) ;
123
- }
124
-
125
93
private void ListeningLoop ( )
126
94
{
127
95
while ( true )
@@ -140,8 +108,14 @@ private void ListeningLoop()
140
108
break ;
141
109
}
142
110
143
- Thread . Sleep ( 2000 ) ;
111
+ Thread . Sleep ( _globalSettings . CurrentValue . MainDomReleaseSignalPollingInterval ) ;
144
112
}
145
113
}
114
+
115
+ public void Dispose ( )
116
+ {
117
+ _lockFileStream ? . Close ( ) ;
118
+ _lockFileStream = null ;
119
+ }
146
120
}
147
121
}
0 commit comments