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));
        }
Exemplo n.º 2
0
        /// <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));
        }