-
Notifications
You must be signed in to change notification settings - Fork 4.8k
/
StorageResponseClassifier.cs
77 lines (68 loc) · 3.28 KB
/
StorageResponseClassifier.cs
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
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using Azure.Core;
namespace Azure.Storage
{
internal class StorageResponseClassifier : ResponseClassifier
{
/// <summary>
/// The secondary URI to be used for retries on failed read requests
/// </summary>
public Uri SecondaryStorageUri { get; set; }
/// <summary>
/// Overridden version of IsRetriableResponse that allows for Storage specific retry logic.
/// </summary>
/// <param name="message">The message containing both Response and Request</param>
/// <returns></returns>
public override bool IsRetriableResponse(HttpMessage message)
{
// If secondary storage Uri was specified, we want to retry if the current attempt was against the secondary Uri, and we
// get a response of NotFound. This is because the resource may not have been propagated to secondary Uri yet.
if (SecondaryStorageUri != null &&
message.Request.Uri.Host == SecondaryStorageUri.Host &&
message.Response.Status == Constants.HttpStatusCode.NotFound)
{
return true;
}
// Retry select Storage service error codes
if (message.Response.Status >= 400 &&
message.Response.Headers.TryGetValue(Constants.HeaderNames.ErrorCode, out var error))
{
switch (error)
{
case Constants.ErrorCodes.InternalError:
case Constants.ErrorCodes.OperationTimedOut:
case Constants.ErrorCodes.ServerBusy:
return true;
}
}
return base.IsRetriableResponse(message);
}
/// <inheritdoc />
public override bool IsErrorResponse(HttpMessage message)
{
switch (message.Response.Status)
{
case 409:
// We're not considering Container/BlobAlreadyExists as errors when the request has conditional headers.
// Convenience methods like BlobContainerClient.CreateIfNotExists will cause a lot of these responses and
// we don't want them polluting AppInsights with noise. See RequestActivityPolicy for how this is applied.
RequestHeaders requestHeaders = message.Request.Headers;
if (message.Response.Headers.TryGetValue(Constants.HeaderNames.ErrorCode, out var error) &&
(error == Constants.ErrorCodes.ContainerAlreadyExists ||
error == Constants.ErrorCodes.BlobAlreadyExists))
{
var isConditional =
requestHeaders.Contains(HttpHeader.Names.IfMatch) ||
requestHeaders.Contains(HttpHeader.Names.IfNoneMatch) ||
requestHeaders.Contains(HttpHeader.Names.IfModifiedSince) ||
requestHeaders.Contains(HttpHeader.Names.IfUnmodifiedSince);
return !isConditional;
}
break;
}
return base.IsErrorResponse(message);
}
}
}