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)); }
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))); }; }
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); }
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); }
public Subscription(IRawConsumer consumer, string queueName) { _consumer = consumer; var basicConsumer = consumer as DefaultBasicConsumer; if (basicConsumer == null) { return; } QueueName = queueName; ConsumerTag = basicConsumer.ConsumerTag; }
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; }
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); }
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); } }
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)); } }
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)); }
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; })); }
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); } }
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; }