-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathAzureStorageLeaseManager.cs
More file actions
90 lines (75 loc) · 3.59 KB
/
AzureStorageLeaseManager.cs
File metadata and controls
90 lines (75 loc) · 3.59 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
using Azure.Storage.Blobs.Models;
using Azure.Storage.Blobs.Specialized;
using Microsoft.Extensions.Options;
using Nhs.Appointments.Core.Blob;
using Polly;
namespace Nhs.Appointments.Core.Concurrency;
internal class AzureStorageLeaseManager : ILeaseManager
{
private readonly IAzureBlobStorage _azureBlobStorage;
private readonly LeaseManagerOptions _defaultOptions;
private readonly int _delayRetryTimeInMilliseconds;
public AzureStorageLeaseManager(
IOptions<LeaseManagerOptions> options,
IAzureBlobStorage azureBlobStorage,
int delayRetryTimeInMilliseconds = 100
)
{
ArgumentOutOfRangeException.ThrowIfLessThanOrEqual(delayRetryTimeInMilliseconds, 0, nameof(delayRetryTimeInMilliseconds));
_azureBlobStorage = azureBlobStorage ?? throw new ArgumentNullException(nameof(azureBlobStorage));
_delayRetryTimeInMilliseconds = delayRetryTimeInMilliseconds;
_defaultOptions = options.Value;
}
public string Mode => LeaseManagerMode.DistributedAzureBlob;
public ILeaseContext Acquire(string leaseKey, LeaseManagerOptions options = null)
{
var leaseClient = GetLeaseClient(ResolveContainerName(options),leaseKey);
CreateResiliencePipeline().Execute(() => leaseClient.Acquire(ResolveTimeout(options)));
return new LeaseContext(leaseKey, () => leaseClient.Release());
}
public async Task<ILeaseContext> AcquireAsync(string leaseKey, LeaseManagerOptions options = null)
{
var leaseClient = await GetLeaseClientAsync(ResolveContainerName(options),leaseKey);
await CreateResiliencePipeline().ExecuteAsync(
async (cancellationToken) => await leaseClient.AcquireAsync(
ResolveTimeout(options),
cancellationToken: cancellationToken));
return new LeaseContext(leaseKey, () => leaseClient.Release());
}
private BlobLeaseClient GetLeaseClient(string containerName, string blobName)
{
var blobClient = _azureBlobStorage.GetBlobClientFromContainerAndBlobName(containerName, blobName);
if (blobClient.Exists() == false)
{
blobClient.Upload(BinaryData.FromString(""));
}
return blobClient.GetBlobLeaseClient();
}
private async Task<BlobLeaseClient> GetLeaseClientAsync(string containerName, string blobName)
{
var blobClient = await _azureBlobStorage.GetBlobClientFromContainerAndBlobNameAsync(containerName, blobName);
if (await blobClient.ExistsAsync() == false)
{
await blobClient.UploadAsync(BinaryData.FromString(""));
}
return blobClient.GetBlobLeaseClient();
}
private ResiliencePipeline<Azure.Response<BlobLease>> CreateResiliencePipeline()
{
return new ResiliencePipelineBuilder<Azure.Response<BlobLease>>()
.AddRetry(new Polly.Retry.RetryStrategyOptions<Azure.Response<BlobLease>>
{
ShouldHandle = arguments => arguments.Outcome switch
{
{ Exception: Azure.RequestFailedException ex } when ex.ErrorCode == "LeaseAlreadyPresent" => PredicateResult.True(),
_ => PredicateResult.False(),
},
MaxRetryAttempts = 20,
Delay = TimeSpan.FromMilliseconds(_delayRetryTimeInMilliseconds)
})
.Build();
}
private string ResolveContainerName(LeaseManagerOptions options = null) => options?.Realm ?? _defaultOptions.Realm;
private TimeSpan ResolveTimeout(LeaseManagerOptions options = null) =>
options?.Timeout ?? _defaultOptions.Timeout;
}