in src/Microsoft.Extensions.Configuration.AzureAppConfiguration/AzureAppConfigurationProvider.cs [1109:1218]
private async Task<T> ExecuteWithFailOverPolicyAsync<T>(
IEnumerable<ConfigurationClient> clients,
Func<ConfigurationClient, Task<T>> funcToExecute,
CancellationToken cancellationToken = default)
{
if (_requestTracingEnabled && _requestTracingOptions != null)
{
_requestTracingOptions.IsFailoverRequest = false;
}
if (_options.LoadBalancingEnabled && _lastSuccessfulEndpoint != null && clients.Count() > 1)
{
int nextClientIndex = 0;
foreach (ConfigurationClient client in clients)
{
nextClientIndex++;
if (_configClientManager.GetEndpointForClient(client) == _lastSuccessfulEndpoint)
{
break;
}
}
// If we found the last successful client, we'll rotate the list so that the next client is at the beginning
if (nextClientIndex < clients.Count())
{
clients = clients.Skip(nextClientIndex).Concat(clients.Take(nextClientIndex));
}
}
using IEnumerator<ConfigurationClient> clientEnumerator = clients.GetEnumerator();
clientEnumerator.MoveNext();
Uri previousEndpoint = _configClientManager.GetEndpointForClient(clientEnumerator.Current);
ConfigurationClient currentClient;
while (true)
{
bool success = false;
bool backoffAllClients = false;
cancellationToken.ThrowIfCancellationRequested();
currentClient = clientEnumerator.Current;
try
{
T result = await funcToExecute(currentClient).ConfigureAwait(false);
success = true;
_lastSuccessfulEndpoint = _configClientManager.GetEndpointForClient(currentClient);
return result;
}
catch (RequestFailedException rfe)
{
if (!IsFailOverable(rfe) || !clientEnumerator.MoveNext())
{
backoffAllClients = true;
throw;
}
}
catch (AggregateException ae)
{
if (!IsFailOverable(ae) || !clientEnumerator.MoveNext())
{
backoffAllClients = true;
throw;
}
}
finally
{
if (!success && backoffAllClients)
{
_logger.LogWarning(LogHelper.BuildLastEndpointFailedMessage(previousEndpoint?.ToString()));
do
{
UpdateClientBackoffStatus(previousEndpoint, success);
clientEnumerator.MoveNext();
currentClient = clientEnumerator.Current;
}
while (currentClient != null);
}
else
{
UpdateClientBackoffStatus(previousEndpoint, success);
}
}
Uri currentEndpoint = _configClientManager.GetEndpointForClient(clientEnumerator.Current);
if (previousEndpoint != currentEndpoint)
{
_logger.LogWarning(LogHelper.BuildFailoverMessage(previousEndpoint?.ToString(), currentEndpoint?.ToString()));
}
previousEndpoint = currentEndpoint;
if (_requestTracingEnabled && _requestTracingOptions != null)
{
_requestTracingOptions.IsFailoverRequest = true;
}
}
}