/// <summary> /// 消费者收到消息之后,处理方法。 /// </summary> /// <param name="context"></param> public void InvokeOnMessageHandler(ConsumerExecutionContext context) { Preconditions.CheckNotNull(context, "context"); ConsoleLogger.DebugWrite("Received \n\tRoutingKey: '{0}'\n\tCorrelationId: '{1}'\n\tConsumerTag: '{2}'\n\tDeliveryTag: {3}\n\tRedelivered: {4}", context.Info.RoutingKey, context.Properties.CorrelationId, context.Info.ConsumerTag, context.Info.DeliverTag, context.Info.Redelivered); Task completionTask; try { completionTask = context.OnMessageHandler(context.Body, context.Properties, context.Info); } catch (Exception exception) { completionTask = TaskHelpers.FromException(exception); } if (completionTask.Status == TaskStatus.Created) { ConsoleLogger.ErrorWrite("Task returned from consumer callback is not started. ConsumerTag: '{0}'", context.Info.ConsumerTag); return; } completionTask.ContinueWith(task => this.DoAck(context, this.GetAckStrategy(context, task))); }
/// <summary> /// 发送ack回执 /// </summary> /// <param name="context"></param> /// <param name="ackStrategy"></param> private void DoAck(ConsumerExecutionContext context, AckStrategy ackStrategy) { const string failedToAckMessage = "Basic ack failed because channel was closed with message '{0}'." + " Message remains on RabbitMQ and will be retried." + " ConsumerTag: {1}, DeliveryTag: {2}"; AckResult ackResult = AckResult.Exception; try { Preconditions.CheckNotNull(context.Consumer.Model, "context.Consumer.Model"); ackResult = ackStrategy(context.Consumer.Model, context.Info.DeliverTag); } catch (AlreadyClosedException alreadyClosedException) { ConsoleLogger.InfoWrite(failedToAckMessage, alreadyClosedException.Message, context.Info.ConsumerTag, context.Info.DeliverTag); } catch (IOException ioException) { ConsoleLogger.InfoWrite(failedToAckMessage, ioException.Message, context.Info.ConsumerTag, context.Info.DeliverTag); } catch (Exception exception) { ConsoleLogger.ErrorWrite("Unexpected exception when attempting to ACK or NACK\n{0}", exception); } finally { EventBus.Instance.Publish(new AckEvent(context, ackResult)); } }
private string DeclareErrorExchangeAndBindToDefaultErrorQueue(IModel model, ConsumerExecutionContext context) { var originalRoutingKey = context.Info.RoutingKey; return(this._errorExchanges.GetOrAdd(originalRoutingKey, _ => { var exchangeName = Conventions.ErrorExchangeNamingConvention(context.Info); model.ExchangeDeclare(exchangeName, ExchangeType.Direct, durable: true); model.QueueBind(Conventions.ErrorQueueNamingConvention(), exchangeName, originalRoutingKey); return exchangeName; })); }
private byte[] CreateErrorMessage(ConsumerExecutionContext context, Exception exception) { var messageAsString = Encoding.UTF8.GetString(context.Body); var error = new FAN.RabbitMQ.Topology.Error { RoutingKey = context.Info.RoutingKey, Exchange = context.Info.Exchange, Exception = exception.ToString(), Message = messageAsString, DateTime = DateTime.Now, BasicProperties = context.Properties }; return(MessageToBytes(error)); }
public virtual AckStrategy HandleConsumerError(ConsumerExecutionContext context, Exception exception) { Preconditions.CheckNotNull(context, "context"); Preconditions.CheckNotNull(exception, "exception"); try { this.Connect(); using (var model = this._connection.CreateModel()) { var errorExchange = DeclareErrorExchangeQueueStructure(model, context); var messageBody = CreateErrorMessage(context, exception); var properties = model.CreateBasicProperties(); properties.SetPersistent(true); properties.Type = TypeNameSerializer.Serialize(typeof(FAN.RabbitMQ.Topology.Error)); model.BasicPublish(errorExchange, context.Info.RoutingKey, properties, messageBody); } } catch (BrokerUnreachableException) { // thrown if the broker is unreachable during initial creation. ConsoleLogger.ErrorWrite("RabbitMQ Consumer Error Handler cannot connect to Broker\n" + CreateConnectionCheckMessage()); } catch (OperationInterruptedException interruptedException) { // thrown if the broker connection is broken during declare or publish. ConsoleLogger.ErrorWrite("RabbitMQ Consumer Error Handler: Broker connection was closed while attempting to publish Error message.\n" + string.Format("Message was: '{0}'\n", interruptedException.Message) + CreateConnectionCheckMessage()); } catch (Exception unexpectedException) { // Something else unexpected has gone wrong :( ConsoleLogger.ErrorWrite("RabbitMQ Consumer Error Handler: Failed to publish error message\nException is:\n" + unexpectedException); } return(AckStrategies.Ack); }
private string BuildErrorMessage(ConsumerExecutionContext context, Exception exception) { var message = Encoding.UTF8.GetString(context.Body); var properties = context.Properties; var propertiesMessage = new StringBuilder(); if (properties != null) { properties.AppendPropertyDebugStringTo(propertiesMessage); } return("Exception thrown by subscription callback.\n" + string.Format("\tExchange: '{0}'\n", context.Info.Exchange) + string.Format("\tRouting Key: '{0}'\n", context.Info.RoutingKey) + string.Format("\tRedelivered: '{0}'\n", context.Info.Redelivered) + string.Format("Message:\n{0}\n", message) + string.Format("BasicProperties:\n{0}\n", propertiesMessage) + string.Format("Exception:\n{0}\n", exception)); }
/// <summary> /// 消费者处理交付。IBasicConsumer接口自动完成调用。 /// </summary> /// <param name="consumerTag"></param> /// <param name="deliveryTag"></param> /// <param name="redelivered"></param> /// <param name="exchange"></param> /// <param name="routingKey"></param> /// <param name="properties"></param> /// <param name="body"></param> public void HandleBasicDeliver(string consumerTag, ulong deliveryTag, bool redelivered, string exchange, string routingKey, IBasicProperties properties, byte[] body) { ConsoleLogger.DebugWrite("HandleBasicDeliver on consumer: {0}, deliveryTag: {1}", consumerTag, deliveryTag); if (this._disposed) { // this message's consumer has stopped, so just return ConsoleLogger.InfoWrite("Consumer has stopped running. Consumer '{0}' on queue '{1}'. Ignoring message", this.ConsumerTag, queue.Name); return; } if (this._onMessage == null) { ConsoleLogger.ErrorWrite("User consumer callback, 'onMessage' has not been set for consumer '{0}'. Please call InternalConsumer.StartConsuming before passing the consumer to basic.consume", this.ConsumerTag); return; } var messageReceivedInfo = new MessageReceivedInfo(consumerTag, deliveryTag, redelivered, exchange, routingKey, queue.Name); var messsageProperties = new MessageProperties(properties); var context = new ConsumerExecutionContext(this._onMessage, messageReceivedInfo, messsageProperties, body, this); this._consumerDispatcher.QueueAction(() => this._handlerRunner.InvokeOnMessageHandler(context)); }
/// <summary> /// 得到ack的策略 /// </summary> /// <param name="context"></param> /// <param name="task"></param> /// <returns></returns> private AckStrategy GetAckStrategy(ConsumerExecutionContext context, Task task) { var ackStrategy = AckStrategies.Ack;//默认返回ack try { if (task.IsFaulted) { ConsoleLogger.ErrorWrite(BuildErrorMessage(context, task.Exception)); ackStrategy = _consumerErrorStrategy.HandleConsumerError(context, task.Exception); } else if (task.IsCanceled) { ackStrategy = this._consumerErrorStrategy.HandleConsumerCancelled(context); } } catch (Exception consumerErrorStrategyError) { ConsoleLogger.ErrorWrite("Exception in ConsumerErrorStrategy:\n{0}", consumerErrorStrategyError); return(AckStrategies.Nothing); } return(ackStrategy); }
public AckStrategy HandleConsumerCancelled(ConsumerExecutionContext context) { return(AckStrategies.Ack); }
private string DeclareErrorExchangeQueueStructure(IModel model, ConsumerExecutionContext context) { this.DeclareDefaultErrorQueue(model); return(DeclareErrorExchangeAndBindToDefaultErrorQueue(model, context)); }
public AckEvent(ConsumerExecutionContext consumerExecutionContext, AckResult ackResult) { ConsumerExecutionContext = consumerExecutionContext; AckResult = ackResult; }