Skip to content

Commit 7e0c8f9

Browse files
LanaparezaninLana Parezanin
andauthored
Updating stats jobs to use new Azure SDK (#10323)
* Fixing gallery build error * Testfix * Bugfix * Added TopLevel * Has right .net sdk version now * Changed toplevel error * Changed toplevel error pt 2 * Changed toplevel error pt 3 * Bugfix * Bugfix2 * Added a comment * Clarified comment * AzureStatsLogDestination is now using new SDK * Temp changes * Changes * AzureStatsLogSource.cs has been updated * Migrated more files and tests * Final fixes? * Fixed failing tests * Fixed blobleasemanager problem * Fixing * Test fixes * Buildfix * Fixed cancellation problem * Latest changes * Polished BlobLeaseService.cs * Polished AzureBlobLockResult.cs * Polished AzureBlobLeaseManager.cs * Polished Job.cs * Fixed CDNLogsSanitizer scripts * Polished tests * Fixed extra semi-colon * Moved throw to new line * Moved throw to new line pt.2 * Changed to explicit type * Added more explicit types * Nit fixes * Added extra comments * Added non-negative waiting time check * Fixed token * Added a new check * Removed unneccessary cancellation token * Added flag * Fixed a nit * Not using BlobLeaseService anymore :( * Re-ordered libraries * Removed commented out code) * Removed more commented out code * Fixing nits * More nits * Removed unnecessary variables * Fix * Added token back * Fixed formating --------- Co-authored-by: Lana Parezanin <[email protected]>
1 parent 8219a5b commit 7e0c8f9

14 files changed

Lines changed: 258 additions & 233 deletions

File tree

src/NuGet.Services.Storage/BlobLeaseService.cs

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
using Azure;
99
using Azure.Storage.Blobs;
1010
using Azure.Storage.Blobs.Specialized;
11+
using Microsoft.Extensions.Logging;
1112

1213
namespace NuGet.Services.Storage
1314
{
@@ -20,11 +21,11 @@ public class BlobLeaseService : IBlobLeaseService
2021
{
2122
private static readonly TimeSpan MinLeaseTime = TimeSpan.FromSeconds(15);
2223
private static readonly TimeSpan MaxLeaseTime = TimeSpan.FromSeconds(60);
23-
2424
private readonly BlobContainerClient _containerClient;
2525
private readonly string _basePath;
26+
private readonly bool _createBlobWhenMissing;
2627

27-
public BlobLeaseService(BlobServiceClient blobServiceClient, string containerName, string basePath)
28+
public BlobLeaseService(BlobServiceClient blobServiceClient, string containerName, string basePath, Boolean createBlobsWhenMissing = true)
2829
{
2930
if (blobServiceClient == null)
3031
{
@@ -34,13 +35,13 @@ public BlobLeaseService(BlobServiceClient blobServiceClient, string containerNam
3435
{
3536
throw new ArgumentException("The container name must be provided.", nameof(containerName));
3637
}
37-
if (string.IsNullOrEmpty(basePath))
38+
if (basePath == null)
3839
{
3940
throw new ArgumentException("The base path must be provided.", nameof(basePath));
4041
}
41-
4242
_containerClient = blobServiceClient.GetBlobContainerClient(containerName);
4343
_basePath = string.IsNullOrEmpty(basePath) ? string.Empty : basePath.TrimEnd('/') + '/';
44+
_createBlobWhenMissing = createBlobsWhenMissing;
4445
}
4546

4647
public async Task<BlobLeaseResult> TryAcquireAsync(string resourceName, TimeSpan leaseTime, CancellationToken cancellationToken)
@@ -54,7 +55,11 @@ public async Task<BlobLeaseResult> TryAcquireAsync(string resourceName, TimeSpan
5455
catch (RequestFailedException ex) when (ex.Status == (int)HttpStatusCode.NotFound)
5556
{
5657
// The lease file does not exist. Try to create it and lease it.
57-
return await TryCreateAndAcquireAsync(blob, leaseTime, cancellationToken);
58+
if (_createBlobWhenMissing)
59+
{
60+
return await TryCreateAndAcquireAsync(blob, leaseTime, cancellationToken);
61+
}
62+
return BlobLeaseResult.Failure();
5863
}
5964
}
6065

@@ -65,7 +70,6 @@ public async Task<bool> ReleaseAsync(string resourceName, string leaseId, Cancel
6570
var blob = GetBlob(resourceName);
6671
var leaseClient = blob.GetBlobLeaseClient(leaseId);
6772
await leaseClient.ReleaseAsync(conditions: null, cancellationToken: cancellationToken);
68-
6973
return true;
7074
}
7175
catch (RequestFailedException ex) when (ex.Status == (int)HttpStatusCode.Conflict)
@@ -94,6 +98,7 @@ public async Task<BlobLeaseResult> RenewAsync(string resourceName, string leaseI
9498
try
9599
{
96100
var lease = await leaseClient.RenewAsync(conditions: null, cancellationToken: cancellationToken);
101+
97102
return BlobLeaseResult.Success(lease);
98103
}
99104
catch (RequestFailedException ex) when (ex.Status == (int)HttpStatusCode.Conflict || ex.Status == (int)HttpStatusCode.PreconditionFailed)
@@ -135,6 +140,7 @@ private async Task<BlobLeaseResult> TryAcquireAsync(BlobClient blob, TimeSpan le
135140
{
136141
var leaseClient = blob.GetBlobLeaseClient();
137142
var blobLease = await leaseClient.AcquireAsync(leaseTime, conditions: null, cancellationToken: cancellationToken);
143+
138144
return BlobLeaseResult.Success(blobLease);
139145
}
140146
catch (RequestFailedException ex) when (ex.Status == (int)HttpStatusCode.Conflict)
Lines changed: 54 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
1-
// Copyright (c) .NET Foundation. All rights reserved.
1+
// Copyright (c) .NET Foundation. All rights reserved.
22
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
33

44
using System;
5+
using System.Net;
56
using System.Threading;
67
using System.Threading.Tasks;
8+
using Azure;
9+
using Azure.Storage.Blobs;
10+
using Azure.Storage.Blobs.Specialized;
711
using Microsoft.Extensions.Logging;
8-
using Microsoft.WindowsAzure.Storage;
9-
using Microsoft.WindowsAzure.Storage.Blob;
12+
using NuGet.Services.Storage;
13+
using Stats.AzureCdnLogs.Common.Collect;
1014

1115
namespace Stats.AzureCdnLogs.Common
1216
{
@@ -19,96 +23,82 @@ public class AzureBlobLeaseManager
1923
public const int MaxRenewPeriodInSeconds = 60;
2024
// The lease will be renewed with a short interval before the the lease expires
2125
public const int OverlapRenewPeriodInSeconds = 20;
22-
private BlobRequestOptions _blobRequestOptions;
2326
private readonly ILogger<AzureBlobLeaseManager> _logger;
2427

25-
public AzureBlobLeaseManager(ILogger<AzureBlobLeaseManager> logger, BlobRequestOptions blobRequestOptions = null)
28+
public AzureBlobLeaseManager(ILogger<AzureBlobLeaseManager> logger)
2629
{
27-
_blobRequestOptions = blobRequestOptions;
2830
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
2931
}
3032

3133
/// <summary>
3234
/// Try to acquire a lease on the blob. If the acquire is successful the lease will be renewed at every 60 seconds.
33-
/// In order to stop the renew task the <see cref="Stats.AzureCdnLogs.Common.AzureBlobLeaseManager.TryReleaseLease(CloudBlob)"/> needs to be invoked
35+
/// In order to stop the renew task the <see cref="Stats.AzureCdnLogs.Common.AzureBlobLeaseManager.TryReleaseLockAsync(AzureBlobLockResult)"/> needs to be invoked
3436
/// or the token to be cancelled.
3537
/// </summary>
3638
/// <param name="blob">The blob to acquire the lease on.</param>
37-
/// <param name="token">A token to cancel the operation.</param>
38-
/// <param name="renewStatusTask">The renew task.</param>
39-
/// <returns>True if the lease was acquired. </returns>
40-
public AzureBlobLockResult AcquireLease(CloudBlob blob, CancellationToken token)
39+
/// <returns>An <see cref="AzureBlobLockResult"/> indicating the result of the lease acquisition.
40+
/// If the lease is successfully acquired, the result will contain the lease ID and a cancellation token
41+
/// source that can be used to stop the lease renewal task.</returns>
42+
public async Task<AzureBlobLockResult> AcquireLease(BlobClient blob, CancellationToken token)
4143
{
42-
blob.FetchAttributes();
43-
if (token.IsCancellationRequested || blob.Properties.LeaseStatus == LeaseStatus.Locked)
44+
try
4445
{
45-
_logger.LogInformation("AcquireLease: The operation was cancelled or the blob lease is already taken. Blob {BlobUri}, Cancellation status {IsCancellationRequested}, BlobLeaseStatus {BlobLeaseStatus}.",
46-
blob.Uri.AbsoluteUri,
47-
token.IsCancellationRequested,
48-
blob.Properties.LeaseStatus);
49-
return AzureBlobLockResult.FailedLockResult(blob);
50-
}
51-
var proposedLeaseId = Guid.NewGuid().ToString();
52-
var leaseId = blob.AcquireLease(TimeSpan.FromSeconds(MaxRenewPeriodInSeconds), proposedLeaseId);
53-
var lockResult = new AzureBlobLockResult(blob: blob, lockIsTaken: true, leaseId: leaseId, linkToken: token);
54-
55-
//start a task that will renew the lease until the token is cancelled or the Release methods was invoked
56-
var renewStatusTask = new Task( (lockresult) =>
46+
var leaseClient = blob.GetBlobLeaseClient();
47+
var leaseResponse = await leaseClient.AcquireAsync(TimeSpan.FromSeconds(MaxRenewPeriodInSeconds));
48+
string leaseId = leaseResponse.Value.LeaseId;
49+
var lockResult = new AzureBlobLockResult(blob, lockIsTaken: true, leaseId, token);
50+
BlobClient leasedBlob = lockResult.Blob;
51+
// Start a task that will renew the lease until the token is cancelled or the Release method is invoked
52+
_ = Task.Run(async () =>
5753
{
58-
var blobLockResult = (AzureBlobLockResult)lockresult;
59-
_logger.LogInformation("RenewLeaseTask: Started for BlobUri {BlobUri}. ThreadId {ThreadId}. IsCancellationRequested {IsCancellationRequested}. LeaseId {LeaseId}",
60-
blob.Uri.AbsoluteUri,
61-
Thread.CurrentThread.ManagedThreadId,
62-
blobLockResult.BlobOperationToken.IsCancellationRequested,
63-
blobLockResult.LeaseId);
6454

6555
int sleepBeforeRenewInSeconds = MaxRenewPeriodInSeconds - OverlapRenewPeriodInSeconds < 0 ? MaxRenewPeriodInSeconds : MaxRenewPeriodInSeconds - OverlapRenewPeriodInSeconds;
66-
if (!blobLockResult.BlobOperationToken.IsCancellationRequested)
56+
57+
while (!lockResult.BlobOperationToken.Token.IsCancellationRequested)
6758
{
68-
while (!blobLockResult.BlobOperationToken.Token.IsCancellationRequested)
59+
try
6960
{
70-
Thread.Sleep(sleepBeforeRenewInSeconds * 1000);
71-
72-
//it will renew the lease only if the lease was not explicitly released
73-
try
74-
{
75-
if (!blobLockResult.Blob.Exists())
76-
{
77-
blobLockResult.BlobOperationToken.Cancel();
78-
break;
79-
}
80-
AccessCondition acc = new AccessCondition { LeaseId = blobLockResult.LeaseId };
81-
blob.RenewLease(accessCondition: acc, options: _blobRequestOptions, operationContext: null);
82-
_logger.LogInformation("RenewLeaseTask: Lease was renewed for BlobUri {BlobUri} and LeaseId {LeaseId}.",
83-
blob.Uri.AbsoluteUri,
84-
blobLockResult.LeaseId);
85-
}
86-
catch (StorageException exception)
61+
await Task.Delay(TimeSpan.FromSeconds(sleepBeforeRenewInSeconds));
62+
if (!await leasedBlob.ExistsAsync())
8763
{
88-
_logger.LogWarning(LogEvents.FailedBlobLease, exception, "RenewLeaseTask: The Lease could not be renewed for BlobUri {BlobUri}. ExpectedLeaseId {LeaseId}. CurrentLeaseId {CurrentLeaseId}.",
89-
blob.Uri.AbsoluteUri,
90-
leaseId,
91-
blobLockResult.LeaseId);
92-
blobLockResult.BlobOperationToken.Cancel();
9364
break;
9465
}
66+
await leaseClient.RenewAsync();
67+
_logger.LogInformation("RenewLeaseTask: Lease was renewed for BlobUri {BlobUri} and LeaseId {LeaseId}.",
68+
blob.Uri.AbsoluteUri,
69+
leaseId);
70+
}
71+
catch (Exception ex)
72+
{
73+
_logger.LogWarning(ex, "RenewLeaseTask: The Lease could not be renewed for BlobUri {BlobUri}. LeaseId {LeaseId}.",
74+
blob.Uri.AbsoluteUri,
75+
leaseId);
76+
lockResult.BlobOperationToken.Cancel();
77+
break;
9578
}
9679
}
97-
}, lockResult, TaskCreationOptions.LongRunning);
98-
renewStatusTask.Start();
99-
return lockResult;
80+
81+
82+
83+
}, lockResult.BlobOperationToken.Token);
84+
return lockResult;
85+
}
86+
catch (Exception ex)
87+
{
88+
_logger.LogError(ex, "AcquireLeaseAsync: Failed to acquire lease for BlobUri {BlobUri}.", blob.Uri.AbsoluteUri);
89+
return AzureBlobLockResult.FailedLockResult(blob);
90+
}
91+
10092
}
10193

10294
public async Task<AsyncOperationResult> TryReleaseLockAsync(AzureBlobLockResult releaseLock)
10395
{
10496
try
10597
{
106-
AccessCondition acc = new AccessCondition();
107-
acc.LeaseId = releaseLock.LeaseId;
108-
if(await releaseLock.Blob.ExistsAsync())
98+
if (await releaseLock.Blob.ExistsAsync())
10999
{
110-
await releaseLock.Blob.ReleaseLeaseAsync(acc, options: _blobRequestOptions, operationContext: null);
111-
releaseLock.BlobOperationToken.Cancel();
100+
var leaseClient = releaseLock.Blob.GetBlobLeaseClient(releaseLock.LeaseId);
101+
await leaseClient.ReleaseAsync();
112102
_logger.LogInformation("ReleaseLockAsync: ReleaseLeaseStatus: {LeaseReleased} on the {BlobUri}.", true, releaseLock.Blob.Uri);
113103
return new AsyncOperationResult(true, null);
114104
}
@@ -124,5 +114,6 @@ public async Task<AsyncOperationResult> TryReleaseLockAsync(AzureBlobLockResult
124114
return new AsyncOperationResult(null, exception);
125115
}
126116
}
117+
127118
}
128119
}

src/Stats.AzureCdnLogs.Common/AzureHelpers/AzureBlobLockResult.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
// Copyright (c) .NET Foundation. All rights reserved.
1+
// Copyright (c) .NET Foundation. All rights reserved.
22
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
33

44
using System;
55
using System.Threading;
6-
using Microsoft.WindowsAzure.Storage.Blob;
6+
using Azure.Storage.Blobs;
77

88
namespace Stats.AzureCdnLogs.Common
99
{
@@ -13,15 +13,15 @@ public class AzureBlobLockResult : IDisposable
1313

1414
public string LeaseId { get; }
1515

16-
public CloudBlob Blob { get; }
16+
public BlobClient Blob { get; }
1717

1818
/// <summary>
1919
/// It will be cancelled when the renew task could not renew the lease.
2020
/// Operations can listen to this cancellation to stop execution once the lease could not be renewed.
2121
/// </summary>
2222
public CancellationTokenSource BlobOperationToken { get; }
2323

24-
public AzureBlobLockResult(CloudBlob blob, bool lockIsTaken, string leaseId, CancellationToken linkToken)
24+
public AzureBlobLockResult(BlobClient blob, bool lockIsTaken, string leaseId, CancellationToken linkToken)
2525
{
2626
Blob = blob ?? throw new ArgumentNullException(nameof(blob));
2727
LockIsTaken = lockIsTaken;
@@ -30,7 +30,7 @@ public AzureBlobLockResult(CloudBlob blob, bool lockIsTaken, string leaseId, Can
3030
LeaseId = leaseId;
3131
}
3232

33-
public static AzureBlobLockResult FailedLockResult(CloudBlob blob)
33+
public static AzureBlobLockResult FailedLockResult(BlobClient blob)
3434
{
3535
return new AzureBlobLockResult(blob: blob, lockIsTaken: false, leaseId: null, linkToken: CancellationToken.None);
3636
}

0 commit comments

Comments
 (0)