|
|
|
@ -5,7 +5,7 @@ using System.Threading.Tasks; |
|
|
|
|
|
|
|
namespace Volo.Abp.Telemetry.Helpers; |
|
|
|
|
|
|
|
static internal class MutexExecutor |
|
|
|
public static class MutexExecutor |
|
|
|
{ |
|
|
|
private const int MaxRetries = 5; |
|
|
|
private const int RetryDelay = 100; |
|
|
|
@ -14,51 +14,50 @@ static internal class MutexExecutor |
|
|
|
public async static Task<TResult?> ExecuteAsync<TResult>(string mutexName, Func<Task<TResult>> action) |
|
|
|
{ |
|
|
|
using var mutex = new Mutex(false, mutexName); |
|
|
|
return await ExecuteWithRetriesAsync(mutex, action); |
|
|
|
} |
|
|
|
|
|
|
|
for (int attempt = 1; attempt <= MaxRetries; attempt++) |
|
|
|
private async static Task<TResult?> ExecuteWithRetriesAsync<TResult>(Mutex mutex, Func<Task<TResult>> action) |
|
|
|
{ |
|
|
|
for (var attempt = 1; attempt <= MaxRetries; attempt++) |
|
|
|
{ |
|
|
|
if (!await WaitAsync(mutex)) |
|
|
|
if (await TryExecuteActionAsync(mutex, action) is { } result) |
|
|
|
{ |
|
|
|
if (attempt == MaxRetries) |
|
|
|
{ |
|
|
|
return default; |
|
|
|
} |
|
|
|
|
|
|
|
await Task.Delay(RetryDelay); |
|
|
|
continue; |
|
|
|
return result; |
|
|
|
} |
|
|
|
|
|
|
|
try |
|
|
|
if (attempt == MaxRetries) |
|
|
|
{ |
|
|
|
return await action(); |
|
|
|
} |
|
|
|
catch (AbandonedMutexException) |
|
|
|
{ |
|
|
|
if (attempt == MaxRetries) |
|
|
|
{ |
|
|
|
return default; |
|
|
|
} |
|
|
|
|
|
|
|
await Task.Delay(RetryDelay); |
|
|
|
return default; |
|
|
|
} |
|
|
|
catch (IOException) |
|
|
|
{ |
|
|
|
if (attempt == MaxRetries) |
|
|
|
{ |
|
|
|
return default; |
|
|
|
} |
|
|
|
|
|
|
|
await Task.Delay(RetryDelay); |
|
|
|
} |
|
|
|
finally |
|
|
|
{ |
|
|
|
ReleaseSafely(mutex); |
|
|
|
} |
|
|
|
await Task.Delay(RetryDelay); |
|
|
|
} |
|
|
|
|
|
|
|
return default; |
|
|
|
} |
|
|
|
|
|
|
|
private async static Task<TResult?> TryExecuteActionAsync<TResult>(Mutex mutex, Func<Task<TResult>> action) |
|
|
|
{ |
|
|
|
if (!await WaitAsync(mutex)) |
|
|
|
{ |
|
|
|
return default; |
|
|
|
} |
|
|
|
|
|
|
|
try |
|
|
|
{ |
|
|
|
return await action(); |
|
|
|
} |
|
|
|
catch (Exception ex) when (ex is AbandonedMutexException or IOException) |
|
|
|
{ |
|
|
|
return default; |
|
|
|
} |
|
|
|
finally |
|
|
|
{ |
|
|
|
ReleaseSafely(mutex); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
private async static Task<bool> WaitAsync(Mutex mutex) |
|
|
|
{ |
|
|
|
return await Task.Run(() => mutex.WaitOne(Timeout)); |
|
|
|
@ -66,10 +65,13 @@ static internal class MutexExecutor |
|
|
|
|
|
|
|
private static void ReleaseSafely(Mutex mutex) |
|
|
|
{ |
|
|
|
try { mutex.ReleaseMutex(); } |
|
|
|
try |
|
|
|
{ |
|
|
|
mutex.ReleaseMutex(); |
|
|
|
} |
|
|
|
catch |
|
|
|
{ |
|
|
|
//ignored
|
|
|
|
// ignored intentionally
|
|
|
|
} |
|
|
|
} |
|
|
|
} |