public async Task ExecutionWithoutRetry()
        {
            RetryHandler retryHandler = new RetryHandler(5, 15, 7, false);

            retryHandler
            .ExcludeForRetry <NullReferenceException>();

            short retryCount = -1;
            short errorCount = 0;

            await retryHandler.ExecuteAsync(async() =>
            {
                retryCount++;

                await Task.Delay(20);

                throw new NullReferenceException();
            },
                                            async (exception, retryIndex, retryLimit) =>
            {
                errorCount++;

                await Task.Delay(10);

                Assert.NotNull(exception);
                Assert.Equal(0, retryIndex);
                Assert.Equal(0, retryLimit);
            });

            Assert.Equal(0, retryCount);
            Assert.Equal(1, errorCount);
        }
Esempio n. 2
0
        public IIncludeForRetry Subscribe <TSubscriber, TRequest>(AbstractValidator <TRequest> validator) where TSubscriber : IResponder <TRequest> where TRequest : class
        {
            //subscriber registration in a container
            Injection.AddTransient(typeof(TSubscriber));

            //retry handler
            IRetry retryHandler = new RetryHandler(MIN_RETRY_DELAY, MAX_RETRY_DELAY, RETRY_LIMIT, true);

            //creates queue and exchange
            string directory    = typeof(TRequest).GetTypeInfo().GetCustomAttribute <BusNamespace>().Directory;
            string subdirectory = typeof(TRequest).GetTypeInfo().GetCustomAttribute <BusNamespace>().Subdirectory;
            string exchange     = "request_" + directory.ToLower() + "_" + subdirectory.ToLower();
            string routingKey   = typeof(TRequest).Name.ToLower();
            string queue        = _appId.ToLower() + "-request-" + directory.ToLower() + "-" + subdirectory.ToLower() + "-" + typeof(TRequest).Name.ToLower();

            _responderChannel.ExchangeDeclare(exchange, ExchangeType.Direct, true, false);
            _responderChannel.QueueDeclare(queue, true, false, false, new Dictionary <string, object> {
                { "x-message-ttl", (int)REQUEST_TIMEOUT }, { "x-queue-mode", "default" }
            });
            _responderChannel.QueueBind(queue, exchange, routingKey);

            //request listener
            EventingBasicConsumer consumer = new EventingBasicConsumer(_responderChannel);

            consumer.Received += (obj, args) =>
            {
                Task.Factory.StartNew(async() =>
                {
                    //request message
                    string messageBody = Encoding.UTF8.GetString(args.Body.ToArray());

                    //tracing data
                    string traceSpanId      = Encoding.UTF8.GetString((byte[])args.BasicProperties.Headers["TraceSpanId"]);
                    string traceId          = Encoding.UTF8.GetString((byte[])args.BasicProperties.Headers["TraceId"]);
                    string traceDisplayName = "Respond-" + directory + "." + subdirectory + "." + typeof(TRequest).Name;

                    //response action
                    ResponseWrapper <object> responseWrapper = null;

                    await retryHandler.ExecuteAsync(async() =>
                    {
                        TRequest messageRequest = _jsonConverter.Deserialize <TRequest>(messageBody);
                        if (validator != null)
                        {
                            await validator.ValidateAndThrowAsync(messageRequest, (directory + "." + subdirectory + "." + messageRequest.GetType().Name + " is not valid"));
                        }

                        using (IServiceScope serviceScope = _serviceProvider.CreateScope())
                            using (ITraceScope traceScope = (traceSpanId != "" && traceId != "") ? new TraceScope(traceSpanId, traceId, traceDisplayName, _tracer) : new TraceScope(traceDisplayName, _tracer))
                            {
                                TSubscriber subscriber = serviceScope.ServiceProvider.GetService <TSubscriber>();
                                subscriber.Bus         = this;
                                subscriber.TraceScope  = traceScope;
                                traceScope.Attributes.Add("AppId", _appId);
                                traceScope.Attributes.Add("MessageId", args.BasicProperties.MessageId);
                                responseWrapper = new ResponseWrapper <object>(await subscriber.RespondAsync(messageRequest));
                            }

                        _logger.Send(new MessageDetail
                        {
                            Id            = args.BasicProperties.MessageId,
                            CorrelationId = args.BasicProperties.CorrelationId,
                            Type          = MessageType.Request,
                            Directory     = directory,
                            Subdirectory  = subdirectory,
                            Name          = typeof(TRequest).Name,
                            Body          = messageBody,
                            AppId         = args.BasicProperties.AppId,
                            Exception     = null,
                            ToRetry       = false
                        });
                    },
                                                    async(exception, retryIndex, retryLimit) =>
                    {
                        responseWrapper = new ResponseWrapper <object>(exception);

                        _logger.Send(new MessageDetail
                        {
                            Id            = args.BasicProperties.MessageId,
                            CorrelationId = args.BasicProperties.CorrelationId,
                            Type          = MessageType.Request,
                            Directory     = directory,
                            Subdirectory  = subdirectory,
                            Name          = typeof(TRequest).Name,
                            Body          = messageBody,
                            AppId         = args.BasicProperties.AppId,
                            Exception     = exception,
                            ToRetry       = retryIndex != retryLimit
                        });

                        await Task.CompletedTask;
                    });

                    //response message
                    if (typeof(TSubscriber).GetMethod("RespondAsync").GetCustomAttribute <FakeResponse>() == null)
                    {
                        messageBody = _jsonConverter.Serialize(responseWrapper);
                        IBasicProperties properties = _responderChannel.CreateBasicProperties();
                        properties.MessageId        = Guid.NewGuid().ToString();
                        properties.Persistent       = false;
                        properties.CorrelationId    = args.BasicProperties.CorrelationId;
                        _responderChannel.BasicPublish("", args.BasicProperties.ReplyTo, properties, Encoding.UTF8.GetBytes(messageBody));

                        _logger.Send(new MessageDetail
                        {
                            Id            = properties.MessageId,
                            CorrelationId = properties.CorrelationId,
                            Type          = MessageType.Response,
                            Directory     = directory,
                            Subdirectory  = subdirectory,
                            Name          = typeof(TRequest).Name,
                            Body          = messageBody,
                            AppId         = args.BasicProperties.AppId,
                            Exception     = null,
                            ToRetry       = false
                        });
                    }

                    //acknowledgment
                    _responderChannel.BasicAck(args.DeliveryTag, false);
                },
                                      _cancellationTokenSource.Token,
                                      TaskCreationOptions.DenyChildAttach,
                                      TaskScheduler.Default);
            };

            _toActivateConsumers.Add(new Tuple <IModel, string, EventingBasicConsumer>(_responderChannel, queue, consumer));

            return(retryHandler);
        }