public async Task ShouldRetryWhenReceiveAnRetryErrorCode(ErrorResponseCode errorCode) { var conn = Substitute.For <IConnection>(); conn.SendAsync(Arg.Any <IRequest <MetadataResponse> >(), Arg.Any <CancellationToken>()) .Returns(x => CreateMetadataResponse(errorCode), x => CreateMetadataResponse(errorCode)); _brokerRouter.Connections.ReturnsForAnyArgs(new List <IConnection> { conn }); var response = await _brokerRouter.GetMetadataAsync(new [] { "Test" }, CancellationToken.None); Received.InOrder(() => { conn.SendAsync(Arg.Any <IRequest <MetadataResponse> >(), Arg.Any <CancellationToken>()); //_log.OnLogged(LogLevel.Warn, It.Is<LogEvent>(e => e.Message.StartsWith("Failed metadata request on attempt 0: Will retry in"))); conn.SendAsync(Arg.Any <IRequest <MetadataResponse> >(), Arg.Any <CancellationToken>()); //_log.OnLogged(LogLevel.Warn, It.Is<LogEvent>(e => e.Message.StartsWith("Failed metadata request on attempt 1: Will retry in"))); conn.SendAsync(Arg.Any <IRequest <MetadataResponse> >(), Arg.Any <CancellationToken>()); }); Assert.That(_log.LogEvents.Any(e => e.Item1 == LogLevel.Warn && e.Item2.Message.StartsWith("Failed metadata request on attempt 0: Will retry in"))); Assert.That(_log.LogEvents.Any(e => e.Item1 == LogLevel.Warn && e.Item2.Message.StartsWith("Failed metadata request on attempt 1: Will retry in"))); Assert.That(_log.LogEvents.Count(e => e.Item1 == LogLevel.Warn && e.Item2.Message.StartsWith("Failed metadata request on attempt")), Is.EqualTo(2)); }
/// <summary> /// Given a collection of server connections, query for the topic metadata. /// </summary> /// <param name="brokerRouter">The router which provides the route and metadata.</param> /// <param name="topicNames">Topics to get metadata information for.</param> /// <param name="cancellationToken"></param> /// <remarks> /// Used by <see cref="BrokerRouter"/> internally. Broken out for better testability, but not intended to be used separately. /// </remarks> /// <returns>MetadataResponse validated to be complete.</returns> internal static async Task <MetadataResponse> GetMetadataAsync(this IBrokerRouter brokerRouter, IEnumerable <string> topicNames, CancellationToken cancellationToken) { var request = new MetadataRequest(topicNames); return(await brokerRouter.Configuration.RefreshRetry.AttemptAsync( async (attempt, timer) => { var response = await brokerRouter.GetMetadataAsync(request, cancellationToken).ConfigureAwait(false); if (response == null) { return new RetryAttempt <MetadataResponse>(null); } var results = response.Brokers .Select(ValidateBroker) .Union(response.Topics.Select(ValidateTopic)) .Where(r => !r.IsValid.GetValueOrDefault()) .ToList(); var exceptions = results.Select(r => r.ToException()).Where(e => e != null).ToList(); if (exceptions.Count == 1) { throw exceptions.Single(); } if (exceptions.Count > 1) { throw new AggregateException(exceptions); } if (results.Count == 0) { return new RetryAttempt <MetadataResponse>(response); } foreach (var result in results.Where(r => !string.IsNullOrEmpty(r.Message))) { brokerRouter.Log.Warn(() => LogEvent.Create(result.Message)); } return RetryAttempt <MetadataResponse> .Retry; }, (attempt, retry) => brokerRouter.Log.Warn(() => LogEvent.Create($"Failed metadata request on attempt {attempt}: Will retry in {retry}")), null, // return the failed response above, resulting in a null (ex, attempt, retry) => { throw ex.PrepareForRethrow(); }, (ex, attempt) => brokerRouter.Log.Warn(() => LogEvent.Create(ex, $"Failed metadata request on attempt {attempt}")), cancellationToken)); }