Skip to content

Commit afab63c

Browse files
NGloreousnglore
and
nglore
authored
Some improvements to HttpSysDelegator logging and retry logic (dotnet#2671)
* Some improvements to HttpSysDelegator logging and retry logic * Addressing PR feedback * Forcing an empty commit. --------- Co-authored-by: nglore <[email protected]>
1 parent eac3441 commit afab63c

File tree

2 files changed

+65
-32
lines changed

2 files changed

+65
-32
lines changed

src/ReverseProxy/Delegation/HttpSysDelegator.cs

Lines changed: 64 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using System;
55
using System.Collections.Concurrent;
66
using System.Data;
7+
using System.Diagnostics;
78
using System.Diagnostics.CodeAnalysis;
89
using System.Linq;
910
using System.Runtime.CompilerServices;
@@ -46,8 +47,8 @@ public void ResetQueue(string queueName, string urlPrefix)
4647
var key = new QueueKey(queueName, urlPrefix);
4748
if (_queues.TryGetValue(key, out var queueWeakRef) && queueWeakRef.TryGetTarget(out var queue))
4849
{
49-
queue.Detach();
50-
Log.QueueReset(_logger, queueName, urlPrefix);
50+
var detachedQueueState = queue.Detach();
51+
Log.QueueReset(_logger, queueName, urlPrefix, detachedQueueState);
5152
}
5253
}
5354
}
@@ -74,7 +75,7 @@ public void DelegateRequest(HttpContext context, DestinationState destination)
7475
return;
7576
}
7677

77-
Delegate(context, destination, _serverDelegationFeature, requestDelegationFeature, queue, _logger, reattachIfNeeded: true);
78+
Delegate(context, destination, _serverDelegationFeature, requestDelegationFeature, queue, _logger, shouldRetry: true);
7879

7980
static void Delegate(
8081
HttpContext context,
@@ -83,38 +84,46 @@ static void Delegate(
8384
IHttpSysRequestDelegationFeature requestDelegationFeature,
8485
DelegationQueue queue,
8586
ILogger logger,
86-
bool reattachIfNeeded)
87+
bool shouldRetry)
8788
{
8889
// Opportunistically retry initialization if it failed previously.
8990
// This helps when the target queue wasn't yet created because
9091
// the target process hadn't yet started up.
9192
var queueState = queue.Initialize(serverDelegationFeature);
9293
if (!queueState.IsInitialized)
9394
{
94-
Log.QueueNotInitialized(logger, destination, queueState.InitializationException);
95+
Log.QueueNotInitialized(logger, destination, queueState, queueState.InitializationException);
9596
context.Response.StatusCode = StatusCodes.Status503ServiceUnavailable;
9697
context.Features.Set<IForwarderErrorFeature>(new ForwarderErrorFeature(ForwarderError.NoAvailableDestinations, queueState.InitializationException));
9798
return;
9899
}
99100

100101
try
101102
{
102-
Log.DelegatingRequest(logger, destination);
103+
Log.DelegatingRequest(logger, destination, queueState);
103104
requestDelegationFeature.DelegateRequest(queueState.Rule);
104105
}
105-
catch (HttpSysException ex) when (reattachIfNeeded && ex.ErrorCode == ERROR_OBJECT_NO_LONGER_EXISTS)
106+
catch (ObjectDisposedException) when (shouldRetry)
106107
{
107-
Log.QueueNoLongerExists(logger, destination.GetHttpSysDelegationQueue(), destination.Model?.Config?.Address, ex);
108+
Log.QueueDisposed(logger, destination.GetHttpSysDelegationQueue(), destination.Model?.Config?.Address);
109+
110+
// Another thread detached/disposed the queue
111+
// Attempt to delegate one more time which will to try re-initialize the queue
112+
Delegate(context, destination, serverDelegationFeature, requestDelegationFeature, queue, logger, shouldRetry: false);
113+
}
114+
catch (HttpSysException ex) when (shouldRetry && ex.ErrorCode == ERROR_OBJECT_NO_LONGER_EXISTS)
115+
{
116+
Log.QueueNoLongerExists(logger, destination.GetHttpSysDelegationQueue(), destination.Model?.Config?.Address, queueState, ex);
108117

109118
// The target queue is gone. Detach from it so that we can try to re-attach.
110119
queue.Detach(queueState);
111120

112121
// Attempt to delegate one more time which will try re-initialize the queue
113-
Delegate(context, destination, serverDelegationFeature, requestDelegationFeature, queue, logger, reattachIfNeeded: false);
122+
Delegate(context, destination, serverDelegationFeature, requestDelegationFeature, queue, logger, shouldRetry: false);
114123
}
115124
catch (Exception ex)
116125
{
117-
Log.DelegationFailed(logger, destination, ex);
126+
Log.DelegationFailed(logger, destination, queueState, ex);
118127
context.Response.StatusCode = StatusCodes.Status503ServiceUnavailable;
119128
context.Features.Set<IForwarderErrorFeature>(new ForwarderErrorFeature(ForwarderError.Request, ex));
120129
}
@@ -253,7 +262,7 @@ public DelegationQueueState Initialize(IServerDelegationFeature delegationFeatur
253262
return state;
254263
}
255264

256-
public void Detach(DelegationQueueState? state = null)
265+
public DelegationQueueState? Detach(DelegationQueueState? state = null)
257266
{
258267
if (state == null || state == _currentState)
259268
{
@@ -262,10 +271,16 @@ public void Detach(DelegationQueueState? state = null)
262271
if (state == null || state == _currentState)
263272
{
264273
_currentState.Rule?.Dispose();
274+
275+
var oldState = _currentState;
265276
_currentState = new DelegationQueueState();
277+
278+
return oldState;
266279
}
267280
}
268281
}
282+
283+
return null;
269284
}
270285

271286
public bool Equals(QueueKey queueKey)
@@ -309,6 +324,13 @@ public DelegationQueueState(Exception ex)
309324
public DelegationRule? Rule { get; }
310325

311326
public Exception? InitializationException { get; }
327+
328+
public string Id { get; } = Activity.Current switch
329+
{
330+
{ IdFormat: ActivityIdFormat.W3C } => Activity.Current.SpanId.ToHexString(),
331+
{ Id: not null } => Activity.Current.Id,
332+
_ => ActivitySpanId.CreateRandom().ToHexString(),
333+
};
312334
}
313335

314336
private readonly struct QueueKey : IEquatable<QueueKey>
@@ -356,30 +378,35 @@ private static class Log
356378
EventIds.DelegationQueueNotFound,
357379
"Failed to get delegation queue for destination '{destinationId}' with queue name '{queueName}' and url prefix '{urlPrefix}'");
358380

359-
private static readonly Action<ILogger, string, string?, string?, Exception?> _queueNotInitialized = LoggerMessage.Define<string, string?, string?>(
381+
private static readonly Action<ILogger, string, string?, string?, string, Exception?> _queueNotInitialized = LoggerMessage.Define<string, string?, string?, string>(
360382
LogLevel.Information,
361383
EventIds.DelegationQueueNotInitialized,
362-
"Delegation queue not initialized for destination '{destinationId}' with queue '{queueName}' and url prefix '{urlPrefix}'.");
384+
"Delegation queue not initialized for destination '{destinationId}' with queue '{queueName}' and url prefix '{urlPrefix}'. Current state id '{stateId}'");
363385

364-
private static readonly Action<ILogger, string?, string?, Exception?> _queueReset = LoggerMessage.Define<string?, string?>(
386+
private static readonly Action<ILogger, string?, string?, string?, Exception?> _queueReset = LoggerMessage.Define<string?, string?, string?>(
365387
LogLevel.Information,
366388
EventIds.DelegationQueueReset,
367-
"Detached from queue with name '{queueName}' and url prefix '{urlPrefix}'");
389+
"Detached from queue with name '{queueName}' and url prefix '{urlPrefix}'. Detached queue state id '{stateId}'");
368390

369-
private static readonly Action<ILogger, string?, string?, Exception?> _queueNoLongerExists = LoggerMessage.Define<string?, string?>(
370-
LogLevel.Information,
391+
private static readonly Action<ILogger, string?, string?, string, Exception?> _queueNoLongerExists = LoggerMessage.Define<string?, string?, string>(
392+
LogLevel.Debug,
371393
EventIds.DelegationQueueNoLongerExists,
372-
"Destination queue with name '{queueName}' and url prefix '{urlPrefix}' no longer exists. Detaching and attempting to re-initialize.");
394+
"Destination queue with name '{queueName}' and url prefix '{urlPrefix}' no longer exists. Detaching and attempting to re-initialize. Current state id '{stateId}'");
395+
396+
private static readonly Action<ILogger, string?, string?, Exception?> _queueDisposed = LoggerMessage.Define<string?, string?>(
397+
LogLevel.Debug,
398+
EventIds.DelegationQueueDisposed,
399+
"Destination queue with name '{queueName}' and url prefix '{urlPrefix}' was disposed. Attempting to re-initialize.");
373400

374-
private static readonly Action<ILogger, string, string?, string?, Exception?> _delegatingRequest = LoggerMessage.Define<string, string?, string?>(
401+
private static readonly Action<ILogger, string, string?, string?, string, Exception?> _delegatingRequest = LoggerMessage.Define<string, string?, string?, string>(
375402
LogLevel.Information,
376403
EventIds.DelegatingRequest,
377-
"Delegating to destination '{destinationId}' with queue '{queueName}' and url prefix '{urlPrefix}'");
404+
"Delegating to destination '{destinationId}' with queue '{queueName}' and url prefix '{urlPrefix}'. Current state id '{stateId}'");
378405

379-
private static readonly Action<ILogger, string, string?, string?, Exception?> _delegationFailed = LoggerMessage.Define<string, string?, string?>(
406+
private static readonly Action<ILogger, string, string?, string?, string, Exception?> _delegationFailed = LoggerMessage.Define<string, string?, string?, string>(
380407
LogLevel.Error,
381408
EventIds.DelegationFailed,
382-
"Failed to delegate request for destination '{destinationId}' with queue name '{queueName}' and url prefix '{urlPrefix}'");
409+
"Failed to delegate request for destination '{destinationId}' with queue name '{queueName}' and url prefix '{urlPrefix}'. Current state id '{stateId}'");
383410

384411
public static void QueueInitFailed(ILogger logger, string destinationId, string queueName, string urlPrefix, Exception? ex)
385412
{
@@ -391,29 +418,34 @@ public static void QueueNotFound(ILogger logger, DestinationState destination)
391418
_queueNotFound(logger, destination.DestinationId, destination.GetHttpSysDelegationQueue(), destination.Model?.Config?.Address, null);
392419
}
393420

394-
public static void QueueNotInitialized(ILogger logger, DestinationState destination, Exception? ex)
421+
public static void QueueNotInitialized(ILogger logger, DestinationState destination, DelegationQueueState queueState, Exception? ex)
422+
{
423+
_queueNotInitialized(logger, destination.DestinationId, destination.GetHttpSysDelegationQueue(), destination.Model?.Config?.Address, queueState.Id, ex);
424+
}
425+
426+
public static void QueueReset(ILogger logger, string queueName, string urlPrefix, DelegationQueueState? detachedQueueState)
395427
{
396-
_queueNotInitialized(logger, destination.DestinationId, destination.GetHttpSysDelegationQueue(), destination.Model?.Config?.Address, ex);
428+
_queueReset(logger, queueName, urlPrefix, detachedQueueState?.Id, null);
397429
}
398430

399-
public static void QueueReset(ILogger logger, string queueName, string urlPrefix)
431+
public static void QueueNoLongerExists(ILogger logger, string? queueName, string? urlPrefix, DelegationQueueState queueState, Exception? ex)
400432
{
401-
_queueReset(logger, queueName, urlPrefix, null);
433+
_queueNoLongerExists(logger, queueName, urlPrefix, queueState.Id, ex);
402434
}
403435

404-
public static void QueueNoLongerExists(ILogger logger, string? queueName, string? urlPrefix, Exception? ex)
436+
public static void QueueDisposed(ILogger logger, string? queueName, string? urlPrefix)
405437
{
406-
_queueNoLongerExists(logger, queueName, urlPrefix, ex);
438+
_queueDisposed(logger, queueName, urlPrefix, null);
407439
}
408440

409-
public static void DelegatingRequest(ILogger logger, DestinationState destination)
441+
public static void DelegatingRequest(ILogger logger, DestinationState destination, DelegationQueueState queueState)
410442
{
411-
_delegatingRequest(logger, destination.DestinationId, destination.GetHttpSysDelegationQueue(), destination.Model?.Config?.Address, null);
443+
_delegatingRequest(logger, destination.DestinationId, destination.GetHttpSysDelegationQueue(), destination.Model?.Config?.Address, queueState.Id, null);
412444
}
413445

414-
public static void DelegationFailed(ILogger logger, DestinationState destination, Exception ex)
446+
public static void DelegationFailed(ILogger logger, DestinationState destination, DelegationQueueState queueState, Exception ex)
415447
{
416-
_delegationFailed(logger, destination.DestinationId, destination.GetHttpSysDelegationQueue(), destination.Model?.Config?.Address, ex);
448+
_delegationFailed(logger, destination.DestinationId, destination.GetHttpSysDelegationQueue(), destination.Model?.Config?.Address, queueState.Id, ex);
417449
}
418450
}
419451
}

src/ReverseProxy/Utilities/EventIds.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,4 +70,5 @@ internal static class EventIds
7070
public static readonly EventId TimeoutNotApplied = new(64, nameof(TimeoutNotApplied));
7171
public static readonly EventId DelegationQueueNoLongerExists = new(65, nameof(DelegationQueueNoLongerExists));
7272
public static readonly EventId ForwardingRequestCancelled = new(66, nameof(ForwardingRequestCancelled));
73+
public static readonly EventId DelegationQueueDisposed = new(67, nameof(DelegationQueueDisposed));
7374
}

0 commit comments

Comments
 (0)