Skip to content

Commit 9f92f54

Browse files
Storage Webjobs BlobReciptManager Classifies "LeaseAlreadyPresent" (Azure#34752)
* BlobReciptManager classifies LeaseAlreadyPresent as non-error * revert sln modification
1 parent e80954a commit 9f92f54

File tree

5 files changed

+136
-41
lines changed

5 files changed

+136
-41
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
using Azure.Core;
5+
using Microsoft.Azure.WebJobs.Extensions.Storage.Common;
6+
7+
namespace Microsoft.Azure.WebJobs.Extensions.Storage.Blobs.Classifiers
8+
{
9+
internal class LeaseAlreadyPresentResponseClassificationHandler : ResponseClassificationHandler
10+
{
11+
private readonly bool isError;
12+
13+
private LeaseAlreadyPresentResponseClassificationHandler(bool isError)
14+
{
15+
this.isError = isError;
16+
}
17+
18+
public override bool TryClassify(HttpMessage message, out bool isError)
19+
{
20+
if (message.Response.Status != 409 ||
21+
!message.Response.Headers.TryGetValue("x-ms-error-code", out string errorCode) ||
22+
errorCode != "LeaseAlreadyPresent")
23+
{
24+
isError = false;
25+
return false;
26+
}
27+
28+
isError = this.isError;
29+
return true;
30+
}
31+
32+
/// <summary>
33+
/// Gets a response classifier for 409 lease already present.
34+
/// </summary>
35+
/// <param name="classifyAsError">Whether to classify this response as an error.</param>
36+
/// <returns>The <see cref="ResponseClassificationHandler"/>.</returns>
37+
public static ResponseClassificationHandler GetClassifier(bool classifyAsError)
38+
{
39+
return new LeaseAlreadyPresentResponseClassificationHandler(classifyAsError);
40+
}
41+
}
42+
}

sdk/storage/Microsoft.Azure.WebJobs.Extensions.Storage.Blobs/src/Listeners/BlobReceiptManager.cs

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,11 @@
99
using System.Threading;
1010
using System.Threading.Tasks;
1111
using Azure;
12+
using Azure.Core;
1213
using Azure.Storage.Blobs;
1314
using Azure.Storage.Blobs.Models;
1415
using Azure.Storage.Blobs.Specialized;
16+
using Microsoft.Azure.WebJobs.Extensions.Storage.Blobs.Classifiers;
1517
using Microsoft.Azure.WebJobs.Extensions.Storage.Common;
1618
using BlobRequestConditions = Azure.Storage.Blobs.Models.BlobRequestConditions;
1719

@@ -122,26 +124,26 @@ await blob.UploadAsync(
122124

123125
public async Task<string> TryAcquireLeaseAsync(BlockBlobClient blob, CancellationToken cancellationToken)
124126
{
127+
var context = new RequestContext()
128+
{
129+
CancellationToken = cancellationToken
130+
};
131+
context.AddClassifier(LeaseAlreadyPresentResponseClassificationHandler.GetClassifier(classifyAsError: false));
132+
125133
try
126134
{
127-
BlobLease lease = await blob.GetBlobLeaseClient().AcquireAsync(LeasePeriod, cancellationToken: cancellationToken).ConfigureAwait(false);
128-
return lease.LeaseId;
135+
Response response = await blob.GetBlobLeaseClient().AcquireAsync(
136+
LeasePeriod,
137+
conditions: null,
138+
context)
139+
.ConfigureAwait(false);
140+
141+
return response.Headers.TryGetValue("x-ms-lease-id", out string leaseId) ? leaseId : null;
129142
}
130-
catch (RequestFailedException exception)
143+
catch (RequestFailedException exception) when (exception.IsNotFoundBlobOrContainerNotFound())
131144
{
132-
if (exception.IsConflictLeaseAlreadyPresent())
133-
{
134-
return null;
135-
}
136-
else if (exception.IsNotFoundBlobOrContainerNotFound())
137-
{
138-
// If someone deleted the receipt, there's no lease to acquire.
139-
return null;
140-
}
141-
else
142-
{
143-
throw;
144-
}
145+
// If someone deleted the receipt, there's no lease to acquire.
146+
return null;
145147
}
146148
}
147149

sdk/storage/Microsoft.Azure.WebJobs.Extensions.Storage.Blobs/src/Microsoft.Azure.WebJobs.Extensions.Storage.Blobs.csproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<Project Sdk="Microsoft.NET.Sdk">
1+
<Project Sdk="Microsoft.NET.Sdk">
22
<PropertyGroup>
33
<TargetFrameworks>$(RequiredTargetFrameworks)</TargetFrameworks>
44
</PropertyGroup>
@@ -14,7 +14,7 @@
1414
<ItemGroup>
1515
<PackageReference Include="Microsoft.Azure.WebJobs" />
1616
<PackageReference Include="Microsoft.Extensions.Azure" />
17-
<PackageReference Include="Azure.Storage.Blobs" />
17+
<ProjectReference Include="$(MSBuildThisFileDirectory)..\..\Azure.Storage.Blobs\src\Azure.Storage.Blobs.csproj" />
1818
<PackageReference Include="Azure.Storage.Queues" />
1919
</ItemGroup>
2020

sdk/storage/Microsoft.Azure.WebJobs.Extensions.Storage.Blobs/src/RequestFailedExceptionExtensions.Blobs.cs

Lines changed: 0 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -32,29 +32,6 @@ public static bool IsConflictBlobAlreadyExists(this RequestFailedException excep
3232
return exception.ErrorCode == "BlobAlreadyExists";
3333
}
3434

35-
/// <summary>
36-
/// Determines whether the exception is due to a 409 Conflict error with the error code LeaseAlreadyPresent.
37-
/// </summary>
38-
/// <param name="exception">The storage exception.</param>
39-
/// <returns>
40-
/// <see langword="true"/> if the exception is due to a 409 Conflict error with the error code
41-
/// LeaseAlreadyPresent; otherwise <see langword="false"/>.
42-
/// </returns>
43-
public static bool IsConflictLeaseAlreadyPresent(this RequestFailedException exception)
44-
{
45-
if (exception == null)
46-
{
47-
throw new ArgumentNullException(nameof(exception));
48-
}
49-
50-
if (exception.Status != 409)
51-
{
52-
return false;
53-
}
54-
55-
return exception.ErrorCode == "LeaseAlreadyPresent";
56-
}
57-
5835
/// <summary>
5936
/// Determines whether the exception is due to a 409 Conflict error with the error code
6037
/// LeaseIdMismatchWithLeaseOperation.
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
using Azure.Core.Diagnostics;
5+
using Azure.Storage.Blobs;
6+
using Azure.Storage.Blobs.Models;
7+
using Azure.Storage.Blobs.Specialized;
8+
using Microsoft.Azure.WebJobs.Extensions.Storage.Blobs.Listeners;
9+
using Microsoft.Azure.WebJobs.Extensions.Storage.Common.Tests;
10+
using NUnit.Framework;
11+
using System;
12+
using System.Collections.Generic;
13+
using System.Threading;
14+
using System.Threading.Tasks;
15+
16+
namespace Microsoft.Azure.WebJobs.Extensions.Storage.Blobs.Tests
17+
{
18+
public class BlobReciptManagerTests
19+
{
20+
private const string ConnectionName = "AzureWebJobsStorage";
21+
private const string ContainerName = "container-blobreciptmanagertests";
22+
private BlobServiceClient blobServiceClient;
23+
24+
[SetUp]
25+
public void SetUp()
26+
{
27+
blobServiceClient = AzuriteNUnitFixture.Instance.GetBlobServiceClient();
28+
blobServiceClient.GetBlobContainerClient(ContainerName).DeleteIfExists();
29+
// make sure our system containers are present
30+
CreateContainer(blobServiceClient, ContainerName);
31+
}
32+
33+
private static BlobContainerClient CreateContainer(BlobServiceClient blobServiceClient, string containerName)
34+
{
35+
var container = blobServiceClient.GetBlobContainerClient(containerName);
36+
container.CreateIfNotExists();
37+
return container;
38+
}
39+
40+
private static BlobContainerClient GetContainerReference(BlobServiceClient blobServiceClient, string containerName)
41+
{
42+
return blobServiceClient.GetBlobContainerClient(containerName);
43+
}
44+
45+
[Test]
46+
public async Task TryAcquireLeaseNotLogLeaseConflict()
47+
{
48+
// Arrange
49+
BlobContainerClient container = GetContainerReference(blobServiceClient, ContainerName);
50+
BlobClient blob = container.GetBlobClient(Guid.NewGuid().ToString());
51+
await blob.UploadAsync(BinaryData.FromString("Hello world"));
52+
53+
BlobLeaseClient leaseClient = blob.GetBlobLeaseClient();
54+
BlobLease lease = await leaseClient.AcquireAsync(BlobLeaseClient.InfiniteLeaseDuration);
55+
56+
// Act
57+
var messages = new List<string>();
58+
using (var listener = new AzureEventSourceListener((e, message) =>
59+
{
60+
if (e.EventSource.Name == "Azure-Core")
61+
{
62+
messages.Add(message);
63+
}
64+
}, System.Diagnostics.Tracing.EventLevel.Warning))
65+
{
66+
await new BlobReceiptManager(blobServiceClient)
67+
.TryAcquireLeaseAsync(container.GetBlockBlobClient(blob.Name), CancellationToken.None);
68+
}
69+
70+
// Assert
71+
Assert.IsEmpty(messages);
72+
}
73+
}
74+
}

0 commit comments

Comments
 (0)