Пример #1
0
        public virtual Task OnResponseHandlerExceptionAsync(IRawConsumer rawConsumer, IConsumerConfiguration cfg, BasicDeliverEventArgs args, Exception exception)
        {
            _logger.LogError($"An unhandled exception was thrown in the response handler for message '{args.BasicProperties.MessageId}'.", exception);
            var innerException = UnwrapInnerException(exception);
            var exceptionInfo  = new MessageHandlerExceptionInformation
            {
                Message       = $"An unhandled exception was thrown when consuming a message\n  MessageId: {args.BasicProperties.MessageId}\n  Queue: '{cfg.Queue.FullQueueName}'\n  Exchange: '{cfg.Exchange.ExchangeName}'\nSee inner exception for more details.",
                ExceptionType = innerException.GetType().FullName,
                StackTrace    = innerException.StackTrace,
                InnerMessage  = innerException.Message
            };

            _logger.LogInformation($"Sending MessageHandlerException with CorrelationId '{args.BasicProperties.CorrelationId}'");
            rawConsumer.Model.BasicPublish(
                exchange: string.Empty,
                routingKey: args.BasicProperties?.ReplyTo ?? string.Empty,
                basicProperties: _propertiesProvider.GetProperties <MessageHandlerExceptionInformation>(p =>
            {
                p.CorrelationId = args.BasicProperties?.CorrelationId ?? string.Empty;
                p.Headers.Add(PropertyHeaders.ExceptionHeader, _messageExceptionName);
            }),
                body: _serializer.Serialize(exceptionInfo)
                );

            if (!cfg.NoAck)
            {
                _logger.LogDebug($"Nack'ing message with delivery tag '{args.DeliveryTag}'.");
                rawConsumer.Model.BasicNack(args.DeliveryTag, false, false);
            }
            return(Task.FromResult(true));
        }
Пример #2
0
        private void WireUpConsumer(IRawConsumer consumer, IConsumerConfiguration cfg)
        {
            consumer.OnMessageAsync = (o, args) =>
            {
                ResponseCompletionSource responseTcs = null;
                return(_errorStrategy.ExecuteAsync(() =>
                {
                    if (_responseDictionary.TryRemove(args.BasicProperties.CorrelationId, out responseTcs))
                    {
                        _logger.LogDebug($"Recived response with correlationId {args.BasicProperties.CorrelationId}.");
                        responseTcs.RequestTimer.Dispose();

                        _errorStrategy.OnResponseRecievedAsync(args, responseTcs);
                        if (responseTcs.Task.IsFaulted)
                        {
                            return _completed;
                        }
                        var response = _serializer.Deserialize(args);
                        responseTcs.TrySetResult(response);
                        return _completed;
                    }
                    _logger.LogWarning($"Unable to find callback for {args.BasicProperties.CorrelationId}.");
                    return _completed;
                }, exception => _errorStrategy.OnResponseRecievedException(consumer, cfg, args, responseTcs, exception)));
            };
        }
Пример #3
0
        public void WireUpContextFeatures <TMessageContext>(TMessageContext context, IRawConsumer consumer, BasicDeliverEventArgs args) where TMessageContext : IMessageContext
        {
            var advancedCtx = context as IAdvancedMessageContext;

            if (advancedCtx == null)
            {
                return;
            }

            advancedCtx.Nack = () =>
            {
                consumer.AcknowledgedTags.Add(args.DeliveryTag);
                consumer.Model.BasicNack(args.DeliveryTag, false, true);
            };

            advancedCtx.RetryLater = timespan =>
            {
                var dlxName     = _conventions.RetryLaterExchangeConvention(timespan);
                var dlQueueName = _conventions.RetryLaterExchangeConvention(timespan);
                var channel     = _channelFactory.CreateChannel();
                channel.ExchangeDeclare(dlxName, ExchangeType.Direct, true, true, null);
                channel.QueueDeclare(dlQueueName, true, false, true, new Dictionary <string, object>
                {
                    { QueueArgument.DeadLetterExchange, args.Exchange },
                    { QueueArgument.Expires, Convert.ToInt32(timespan.Add(TimeSpan.FromSeconds(1)).TotalMilliseconds) },
                    { QueueArgument.MessageTtl, Convert.ToInt32(timespan.TotalMilliseconds) }
                });
                channel.QueueBind(dlQueueName, dlxName, args.RoutingKey, null);
                UpdateHeaders(args.BasicProperties);
                channel.BasicPublish(dlxName, args.RoutingKey, args.BasicProperties, args.Body);
                channel.QueueUnbind(dlQueueName, dlxName, args.RoutingKey, null);
            };

            advancedCtx.RetryInfo = GetRetryInformatino(args.BasicProperties);
        }
Пример #4
0
        public virtual Task OnResponseHandlerExceptionAsync(IRawConsumer rawConsumer, IConsumerConfiguration cfg, BasicDeliverEventArgs args, Exception exception)
        {
            _logger.LogError($"An unhandled exception was thrown in the response handler for message '{args.BasicProperties.MessageId}'.", exception);
            var innerException = UnwrapInnerException(exception);
            var rawException = new MessageHandlerException(
                message: $"An unhandled exception was thrown when consuming a message\n  MessageId: {args.BasicProperties.MessageId}\n  Queue: '{cfg.Queue.FullQueueName}'\n  Exchange: '{cfg.Exchange.ExchangeName}'\nSee inner exception for more details.",
                inner: innerException
            );

            _logger.LogInformation($"Sending MessageHandlerException with CorrelationId '{args.BasicProperties.CorrelationId}'");
            rawConsumer.Model.BasicPublish(
                exchange: string.Empty,
                routingKey: args.BasicProperties?.ReplyTo ?? string.Empty,
                basicProperties: _propertiesProvider.GetProperties<MessageHandlerException>(p =>
                {
                    p.CorrelationId = args.BasicProperties?.CorrelationId ?? string.Empty;
                    p.Headers.Add(PropertyHeaders.ExceptionHeader, _messageExceptionName);
                }),
                body: _serializer.Serialize(rawException)
            );

            if (!cfg.NoAck)
            {
                _logger.LogDebug($"Nack'ing message with delivery tag '{args.DeliveryTag}'.");
                rawConsumer.Model.BasicNack(args.DeliveryTag, false, false);
            }
            return Task.FromResult(true);
        }
Пример #5
0
		public Subscription(IRawConsumer consumer, string queueName)
		{
			_consumer = consumer;
			var basicConsumer = consumer as DefaultBasicConsumer;
			if (basicConsumer == null)
			{
				return;
			}
			QueueName = queueName;
			ConsumerTag = basicConsumer.ConsumerTag;
		}
Пример #6
0
        public Subscription(IRawConsumer consumer, string queueName)
        {
            _consumer = consumer;
            var basicConsumer = consumer as DefaultBasicConsumer;

            if (basicConsumer == null)
            {
                return;
            }
            QueueName   = queueName;
            ConsumerTag = basicConsumer.ConsumerTag;
        }
Пример #7
0
        public void WireUpContextFeatures <TMessageContext>(TMessageContext context, IRawConsumer consumer, BasicDeliverEventArgs args) where TMessageContext : IMessageContext
        {
            var contextEnhancer = new ContextEnhancer(_channelFactory, _conventions);

            contextEnhancer.WireUpContextFeatures(context, consumer, args);

            var detailedContext = context as IDetailedContext;

            if (detailedContext == null)
            {
                return;
            }

            detailedContext.Exchange   = args.Exchange;
            detailedContext.RoutingKey = args.Exchange;
        }
Пример #8
0
        public void WireUpContextFeatures <TMessageContext>(TMessageContext context, IRawConsumer consumer, BasicDeliverEventArgs args) where TMessageContext : IMessageContext
        {
            if (context == null)
            {
                return;
            }

            var advancedCtx = context as IAdvancedMessageContext;

            if (advancedCtx == null)
            {
                return;
            }

            advancedCtx.Nack = () =>
            {
                consumer.AcknowledgedTags.Add(args.DeliveryTag);
                consumer.Model.BasicNack(args.DeliveryTag, false, true);
            };

            advancedCtx.RetryLater = timespan =>
            {
                var dlxName     = _conventions.DeadLetterExchangeNamingConvention();
                var dlQueueName = _conventions.RetryQueueNamingConvention();
                var channel     = _channelFactory.CreateChannel();
                channel.ExchangeDeclare(dlxName, ExchangeType.Direct);
                channel.QueueDeclare(dlQueueName, false, false, true, new Dictionary <string, object>
                {
                    { QueueArgument.DeadLetterExchange, args.Exchange },
                    { QueueArgument.MessageTtl, Convert.ToInt32(timespan.TotalMilliseconds) }
                });
                channel.QueueBind(dlQueueName, dlxName, args.RoutingKey, null);
                UpdateHeaders(args.BasicProperties);
                channel.BasicPublish(dlxName, args.RoutingKey, args.BasicProperties, args.Body);
                Timer disposeChannel = null;
                disposeChannel = new Timer(state =>
                {
                    channel.QueueDelete(dlQueueName);                     //TODO: investigate why auto-delete doesn't work?
                    channel.Dispose();
                    disposeChannel?.Dispose();
                }, null, timespan.Add(TimeSpan.FromMilliseconds(20)), new TimeSpan(-1));
            };

            advancedCtx.RetryInfo = GetRetryInformatino(args.BasicProperties);
        }
Пример #9
0
        public virtual async Task OnSubscriberExceptionAsync(IRawConsumer consumer, SubscriptionConfiguration config, BasicDeliverEventArgs args, Exception exception)
        {
            if (!config.NoAck)
            {
                consumer.Model.BasicAck(args.DeliveryTag, false);
                consumer.AcknowledgedTags.Add(args.DeliveryTag);
            }
            try
            {
                _logger.LogError($"Error thrown in Subscriber: ", exception);
                _logger.LogDebug($"Attempting to publish message '{args.BasicProperties.MessageId}' to error exchange.");

                await _topologyProvider.DeclareExchangeAsync(_errorExchangeCfg);

                var channel = await _channelFactory.GetChannelAsync();

                var msg             = _serializer.Deserialize(args);
                var actualException = UnwrapInnerException(exception);
                var errorMsg        = new HandlerExceptionMessage
                {
                    Exception = new ExceptionInformation
                    {
                        ExceptionType = actualException.GetType().FullName,
                        InnerMessage  = actualException.InnerException?.Message,
                        Message       = actualException.Message,
                        StackTrace    = actualException.StackTrace
                    },
                    Time    = DateTime.Now,
                    Host    = Environment.MachineName,
                    Message = msg,
                };
                channel.BasicPublish(
                    exchange: _errorExchangeCfg.ExchangeName,
                    routingKey: args.RoutingKey,
                    basicProperties: args.BasicProperties,
                    body: _serializer.Serialize(errorMsg)
                    );
                channel.Close();
            }
            catch (Exception e)
            {
                _logger.LogWarning($"Unable to publish message '{args.BasicProperties.MessageId}' to default error exchange.", e);
            }
        }
Пример #10
0
        public virtual Task OnSubscriberExceptionAsync(IRawConsumer consumer, SubscriptionConfiguration config, BasicDeliverEventArgs args, Exception exception)
        {
            if (!config.NoAck)
            {
                consumer.Model.BasicAck(args.DeliveryTag, false);
                consumer.AcknowledgedTags.Add(args.DeliveryTag);
            }
            try
            {
                _logger.LogError($"Error thrown in Subscriber: ", exception);
                _logger.LogDebug($"Attempting to publish message '{args.BasicProperties.MessageId}' to error exchange.");

                var topologyTask = _topologyProvider.DeclareExchangeAsync(_errorExchangeCfg);
                var channelTask  = _channelFactory.GetChannelAsync();
                return(Task
                       .WhenAll(topologyTask, channelTask)
                       .ContinueWith(t =>
                {
                    var msg = _serializer.Deserialize(args);
                    var errorMsg = new HandlerExceptionMessage
                    {
                        Exception = exception,
                        Time = DateTime.Now,
                        Host = Environment.MachineName,
                        Message = msg,
                    };
                    channelTask.Result.BasicPublish(
                        exchange: _errorExchangeCfg.ExchangeName,
                        routingKey: args.RoutingKey,
                        basicProperties: args.BasicProperties,
                        body: _serializer.Serialize(errorMsg)
                        );
                    channelTask.Result.Close();
                }));
            }
            catch (Exception e)
            {
                _logger.LogWarning($"Unable to publish message '{args.BasicProperties.MessageId}' to default error exchange.", e);
                return(Task.FromResult(true));
            }
        }
Пример #11
0
 public virtual Task OnResponseRecievedException(IRawConsumer rawConsumer, IConsumerConfiguration cfg, BasicDeliverEventArgs args, TaskCompletionSource <object> responseTcs, Exception exception)
 {
     _logger.LogError($"An exception was thrown when recieving response to messaeg '{args.BasicProperties.MessageId}' with CorrelationId '{args.BasicProperties.CorrelationId}'.", exception);
     responseTcs.TrySetException(exception);
     return(Task.FromResult(true));
 }
Пример #12
0
        private Task <TResponse> SendRequestAsync <TRequest, TResponse>(TRequest message, Guid globalMessageId, RequestConfiguration cfg, IRawConsumer consumer)
        {
            var correlationId  = Guid.NewGuid().ToString();
            var responseSource = new ResponseCompletionSource
            {
                RequestTimer = new Timer(state =>
                {
                    ResponseCompletionSource rcs;
                    if (!_responseDictionary.TryRemove(correlationId, out rcs))
                    {
                        _logger.LogWarning($"Unable to find request timer for {correlationId}.");
                        return;
                    }
                    rcs.RequestTimer?.Dispose();
                    rcs.TrySetException(
                        new TimeoutException($"The request '{correlationId}' timed out after {_config.RequestTimeout.ToString("g")}."));
                }, null, _config.RequestTimeout, new TimeSpan(-1))
            };

            _responseDictionary.TryAdd(correlationId, responseSource);

            consumer.Model.BasicPublish(
                exchange: cfg.Exchange.ExchangeName,
                routingKey: _config.RouteWithGlobalId ? $"{cfg.RoutingKey}.{globalMessageId}" : cfg.RoutingKey,
                basicProperties: _propertiesProvider.GetProperties <TResponse>(p =>
            {
                p.ReplyTo       = cfg.ReplyQueue.QueueName;
                p.CorrelationId = correlationId;
                p.Expiration    = _config.RequestTimeout.TotalMilliseconds.ToString();
                p.Headers.Add(PropertyHeaders.Context, _contextProvider.GetMessageContext(globalMessageId));
            }),
                body: _serializer.Serialize(message)
                );
            return(responseSource.Task.ContinueWith(tResponse =>
            {
                if (tResponse.IsFaulted)
                {
                    throw tResponse.Exception?.InnerException ?? new Exception("Failed to recieve response");
                }
                return (TResponse)tResponse.Result;
            }));
        }
Пример #13
0
        public virtual Task OnSubscriberExceptionAsync(IRawConsumer consumer, SubscriptionConfiguration config, BasicDeliverEventArgs args, Exception exception)
        {
            if (!config.NoAck)
            {
                consumer.Model.BasicAck(args.DeliveryTag, false);
                consumer.AcknowledgedTags.Add(args.DeliveryTag);
            }
            try
            {
                _logger.LogDebug($"Attempting to publish message '{args.BasicProperties.MessageId}' to error exchange.");

                var topologyTask = _topologyProvider.DeclareExchangeAsync(_errorExchangeCfg);
                var channelTask = _channelFactory.GetChannelAsync();
                return Task
                    .WhenAll(topologyTask, channelTask)
                    .ContinueWith(t =>
                    {
                        var msg = _serializer.Deserialize(args);
                        var errorMsg = new HandlerExceptionMessage
                        {
                            Exception = exception,
                            Time = DateTime.Now,
                            Host = Environment.MachineName,
                            Message = msg,
                        };
                        consumer.Model.BasicPublish(
                            exchange: _errorExchangeCfg.ExchangeName,
                            routingKey: args.RoutingKey,
                            basicProperties: args.BasicProperties,
                            body: _serializer.Serialize(errorMsg)
                            );
                    });
            }
            catch (Exception e)
            {
                _logger.LogWarning($"Unable to publish message '{args.BasicProperties.MessageId}' to default error exchange.", e);
                return Task.FromResult(true);
            }
        }
Пример #14
0
 public virtual Task OnResponseRecievedException(IRawConsumer rawConsumer, IConsumerConfiguration cfg, BasicDeliverEventArgs args, TaskCompletionSource<object> responseTcs, Exception exception)
 {
     _logger.LogError($"An exception was thrown when recieving response to messaeg '{args.BasicProperties.MessageId}' with CorrelationId '{args.BasicProperties.CorrelationId}'.", exception);
     responseTcs.TrySetException(exception);
     return Task.FromResult(true);
 }
 public override Task OnSubscriberExceptionAsync(IRawConsumer consumer, SubscriptionConfiguration config, BasicDeliverEventArgs args,
                                                 Exception exception)
 {
     throw exception;
 }
Пример #16
0
		public virtual async Task OnSubscriberExceptionAsync(IRawConsumer consumer, SubscriptionConfiguration config, BasicDeliverEventArgs args, Exception exception)
		{
			if (!config.NoAck)
			{
				consumer.Model.BasicAck(args.DeliveryTag, false);
				consumer.AcknowledgedTags.Add(args.DeliveryTag);
			}
			try
			{
				_logger.LogError($"Error thrown in Subscriber: ", exception);
				_logger.LogDebug($"Attempting to publish message '{args.BasicProperties.MessageId}' to error exchange.");

				await _topologyProvider.DeclareExchangeAsync(_errorExchangeCfg);
				var channel = await _channelFactory.GetChannelAsync();
				var msg = _serializer.Deserialize(args);
				var actualException = UnwrapInnerException(exception);
				var errorMsg = new HandlerExceptionMessage
				{
					Exception = new ExceptionInformation
					{
						ExceptionType = actualException.GetType().FullName,
						InnerMessage = actualException.InnerException?.Message,
						Message = actualException.Message,
						StackTrace = actualException.StackTrace
					},
					Time = DateTime.Now,
					Host = Environment.MachineName,
					Message = msg,
				};
				channel.BasicPublish(
					exchange: _errorExchangeCfg.ExchangeName,
					routingKey: args.RoutingKey,
					basicProperties: args.BasicProperties,
					body: _serializer.Serialize(errorMsg)
					);
				channel.Close();
			}
			catch (Exception e)
			{
				_logger.LogWarning($"Unable to publish message '{args.BasicProperties.MessageId}' to default error exchange.", e);
			}
		}