-
Notifications
You must be signed in to change notification settings - Fork 287
/
ErrorHandlingTransmissionPolicy.cs
145 lines (131 loc) · 6.2 KB
/
ErrorHandlingTransmissionPolicy.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
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
namespace Microsoft.ApplicationInsights.WindowsServer.TelemetryChannel.Implementation.TransmissionPolicy
{
using System;
using System.Globalization;
using System.Threading.Tasks;
using Microsoft.ApplicationInsights.Channel.Implementation;
using Microsoft.ApplicationInsights.Extensibility.Implementation;
internal class ErrorHandlingTransmissionPolicy : TransmissionPolicy, IDisposable
{
private BackoffLogicManager backoffLogicManager;
private TaskTimerInternal pauseTimer = new TaskTimerInternal { Delay = TimeSpan.FromSeconds(BackoffLogicManager.SlotDelayInSeconds) };
public override void Initialize(Transmitter transmitter)
{
if (transmitter == null)
{
throw new ArgumentNullException(nameof(transmitter));
}
this.backoffLogicManager = transmitter.BackoffLogicManager;
base.Initialize(transmitter);
transmitter.TransmissionSent += this.HandleTransmissionSentEvent;
}
public void Dispose()
{
this.Dispose(true);
GC.SuppressFinalize(this);
}
private static void AdditionalVerboseTracing(string httpResponse)
{
// For perf reason deserialize the response only when verbose tracing is enabled
if (TelemetryChannelEventSource.IsVerboseEnabled && httpResponse != null)
{
try
{
BackendResponse backendResponse = BackoffLogicManager.GetBackendResponse(httpResponse);
if (backendResponse != null && backendResponse.Errors != null)
{
foreach (var error in backendResponse.Errors)
{
if (error != null)
{
TelemetryChannelEventSource.Log.ItemRejectedByEndpointWarning(error.Message);
}
}
}
}
catch (Exception)
{
// This code is for tracing purposes only; it cannot not throw
}
}
}
private void HandleTransmissionSentEvent(object sender, TransmissionProcessedEventArgs e)
{
HttpWebResponseWrapper httpWebResponseWrapper = e.Response;
if (httpWebResponseWrapper != null)
{
AdditionalVerboseTracing(httpWebResponseWrapper.Content);
if (httpWebResponseWrapper.StatusCode == ResponseStatusCodes.Success || httpWebResponseWrapper.StatusCode == ResponseStatusCodes.PartialSuccess)
{
// There is no further action for ErrorHandlingTransmissionPolicy here as transmission is success/partial success.
return;
}
switch (httpWebResponseWrapper.StatusCode)
{
case ResponseStatusCodes.BadGateway:
case ResponseStatusCodes.GatewayTimeout:
case ResponseStatusCodes.RequestTimeout:
case ResponseStatusCodes.ServiceUnavailable:
case ResponseStatusCodes.InternalServerError:
case ResponseStatusCodes.UnknownNetworkError:
// Disable sending and buffer capacity (Enqueue will enqueue to the Storage)
this.MaxSenderCapacity = 0;
this.MaxBufferCapacity = 0;
this.LogCapacityChanged();
this.Apply();
this.backoffLogicManager.ReportBackoffEnabled((int)httpWebResponseWrapper.StatusCode);
this.Transmitter.Enqueue(e.Transmission);
this.pauseTimer.Delay = this.backoffLogicManager.GetBackOffTimeInterval(httpWebResponseWrapper.RetryAfterHeader);
this.pauseTimer.Start(
() =>
{
this.MaxBufferCapacity = null;
this.MaxSenderCapacity = null;
this.LogCapacityChanged();
this.Apply();
this.backoffLogicManager.ReportBackoffDisabled();
return Task.FromResult<object>(null);
});
break;
default:
// We are losing data here but that is intentional as the response code is
// not in the whitelisted set to attempt retry.
TelemetryChannelEventSource.Log.TransmissionDataNotRetriedForNonWhitelistedResponse(e.Transmission.Id,
httpWebResponseWrapper.StatusCode.ToString(CultureInfo.InvariantCulture));
// For non white listed response, set the result of FlushAsync to false.
e.Transmission.IsFlushAsyncInProgress = false;
break;
}
}
else
{
// Data loss Unknown Exception
// We are losing data here (we did not upload failed transaction back).
// We got unknown exception.
if (e.Exception != null)
{
TelemetryChannelEventSource.Log.TransmissionDataLossError(e.Transmission.Id,
e.Exception.Message);
}
else
{
TelemetryChannelEventSource.Log.TransmissionDataLossError(e.Transmission.Id,
"Unknown Exception Message");
}
// For Unknown Exception set the result of FlushAsync to false.
e.Transmission.IsFlushAsyncInProgress = false;
}
}
private void Dispose(bool disposing)
{
if (disposing)
{
if (this.pauseTimer != null)
{
this.pauseTimer.Dispose();
this.pauseTimer = null;
}
}
}
}
}