private void HandleMessageDelivery(BasicDeliverEventArgs basicDeliverEventArgs) { var consumerTag = basicDeliverEventArgs.ConsumerTag; if (!subscriptions.ContainsKey(consumerTag)) { logger.DebugWrite("No subscription for consumerTag: {0}", consumerTag); return; } var subscriptionInfo = subscriptions[consumerTag]; if (!subscriptionInfo.Consumer.IsRunning) { // this message's consumer has stopped, so just return logger.DebugWrite("Consumer has stopped running. ConsumerTag: {0}", consumerTag); return; } logger.DebugWrite("Recieved \n\tRoutingKey: '{0}'\n\tCorrelationId: '{1}'\n\tConsumerTag: '{2}'", basicDeliverEventArgs.RoutingKey, basicDeliverEventArgs.BasicProperties.CorrelationId, consumerTag); try { var completionTask = subscriptionInfo.Callback( consumerTag, basicDeliverEventArgs.DeliveryTag, basicDeliverEventArgs.Redelivered, basicDeliverEventArgs.Exchange, basicDeliverEventArgs.RoutingKey, basicDeliverEventArgs.BasicProperties, basicDeliverEventArgs.Body); completionTask.ContinueWith(task => { if (task.IsFaulted) { var exception = task.Exception; HandleErrorInSubscriptionHandler(basicDeliverEventArgs, subscriptionInfo, exception); } else { DoAck(basicDeliverEventArgs, subscriptionInfo); } }); } catch (Exception exception) { HandleErrorInSubscriptionHandler(basicDeliverEventArgs, subscriptionInfo, exception); } finally { if (subscriptionInfo.ModelIsSingleUse) { subscriptions.Remove(consumerTag); } } }
void TryToConnect(object timer) { if (timer != null) { ((Timer)timer).Dispose(); } logger.DebugWrite("Trying to connect"); if (disposed) { return; } connectionFactory.Reset(); do { try { connection = connectionFactory.CreateConnection(); // A possible dispose race condition exists, whereby the Dispose() method may run while this loop is waiting on connectionFactory.CreateConnection() returning a connection. In that case, a connection could be created and assigned to the connection variable, without it ever being later disposed, leading to app hang on shutdown. The following if clause guards against this condition and ensures such connections are always disposed. if (disposed) { connection.Dispose(); break; } connectionFactory.Success(); } catch (SocketException socketException) { LogException(socketException); } catch (BrokerUnreachableException brokerUnreachableException) { LogException(brokerUnreachableException); } } while (!disposed && connectionFactory.Next()); if (connectionFactory.Succeeded) { connection.ConnectionShutdown += OnConnectionShutdown; connection.ConnectionBlocked += OnConnectionBlocked; connection.ConnectionUnblocked += OnConnectionUnblocked; OnConnected(); logger.InfoWrite("Connected to RabbitMQ. Broker: '{0}', Port: {1}, VHost: '{2}'", connectionFactory.CurrentHost.Host, connectionFactory.CurrentHost.Port, connectionFactory.Configuration.VirtualHost); } else { if (!disposed) { logger.ErrorWrite("Failed to connect to any Broker. Retrying in {0}", connectionFactory.Configuration.ConnectIntervalAttempt); StartTryToConnect(); } } }
public void Start() { log.DebugWrite("Starting SchedulerService"); bus.Subscribe <ScheduleMe>(schedulerSubscriptionId, OnMessage); publishTimer = new System.Threading.Timer(OnPublishTimerTick, null, 0, configuration.PublishIntervalSeconds * 1000); purgeTimer = new System.Threading.Timer(OnPurgeTimerTick, null, 0, configuration.PurgeIntervalSeconds * 1000); }
private void OnConnectionDisconnected(ConnectionDisconnectedEvent @event) { if (!disconnected) { disconnected = true; channel = null; logger.DebugWrite("Persistent channel disconnected."); } }
public virtual void Subscribe(IQueue queue, Func <Byte[], MessageProperties, MessageReceivedInfo, Task> onMessage) { if (queue == null) { throw new ArgumentNullException("queue"); } if (onMessage == null) { throw new ArgumentNullException("onMessage"); } if (disposed) { throw new EasyNetQException("This bus has been disposed"); } var subscriptionAction = new SubscriptionAction(queue.IsSingleUse); subscriptionAction.Action = () => { var channel = connection.CreateModel(); channel.ModelShutdown += (model, reason) => logger.DebugWrite("Model Shutdown for queue: '{0}'", queue.Name); queue.Visit(new TopologyBuilder(channel)); channel.BasicQos(0, connectionConfiguration.PrefetchCount, false); var consumer = consumerFactory.CreateConsumer(subscriptionAction, channel, queue.IsSingleUse, (consumerTag, deliveryTag, redelivered, exchange, routingKey, properties, body) => { var messageRecievedInfo = new MessageReceivedInfo { ConsumerTag = consumerTag, DeliverTag = deliveryTag, Redelivered = redelivered, Exchange = exchange, RoutingKey = routingKey }; var messsageProperties = new MessageProperties(properties); return(onMessage(body, messsageProperties, messageRecievedInfo)); }); channel.BasicConsume( queue.Name, // queue NoAck, // noAck consumer.ConsumerTag, // consumerTag consumer); // consumer logger.DebugWrite("Declared Consumer. queue='{0}', prefetchcount={1}", queue.Name, connectionConfiguration.PrefetchCount); }; AddSubscriptionAction(subscriptionAction); }
private void Cancel() { logger.DebugWrite("Consumer {0} cancelled", ConsumerTag); IsRunning = false; // copy to temp variable to be thread safe. var cancelled = Cancelled; if (cancelled != null) { cancelled(this); } }
void TryToConnect(object timer) { if (timer != null) { ((Timer)timer).Dispose(); } logger.DebugWrite("Trying to connect"); if (disposed) { return; } connectionFactory.Reset(); do { try { connection = connectionFactory.CreateConnection(); connectionFactory.Success(); } catch (SocketException socketException) { LogException(socketException); } catch (BrokerUnreachableException brokerUnreachableException) { LogException(brokerUnreachableException); } } while (connectionFactory.Next()); if (connectionFactory.Succeeded) { connection.ConnectionShutdown += OnConnectionShutdown; connection.ConnectionBlocked += OnConnectionBlocked; connection.ConnectionUnblocked += OnConnectionUnblocked; OnConnected(); logger.InfoWrite("Connected to RabbitMQ. Broker: '{0}', Port: {1}, VHost: '{2}'", connectionFactory.CurrentHost.Host, connectionFactory.CurrentHost.Port, connectionFactory.Configuration.VirtualHost); } else { logger.ErrorWrite("Failed to connect to any Broker. Retrying in {0} ms\n", connectAttemptIntervalMilliseconds); StartTryToConnect(); } }
void TryToConnect(object timer) { if (timer != null) { ((Timer)timer).Dispose(); } logger.DebugWrite("Trying to connect"); if (disposed) { return; } try { connection = connectionFactory.CreateConnection(); connection.ConnectionShutdown += OnConnectionShutdown; if (Connected != null) { Connected(); } logger.InfoWrite("Connected to RabbitMQ. Broker: '{0}', VHost: '{1}'", connectionFactory.HostName, connectionFactory.VirtualHost); } catch (BrokerUnreachableException brokerUnreachableException) { logger.ErrorWrite("Failed to connect to Broker: '{0}', VHost: '{1}'. Retrying in {2} ms\n" + "Check HostName, VirtualHost, Username and Password.\n" + "ExceptionMessage: {3}", connectionFactory.HostName, connectionFactory.VirtualHost, connectAttemptIntervalMilliseconds, brokerUnreachableException.Message); StartTryToConnect(); } }
/// <inheritdoc /> public override void InvokeUserMessageHandler(ConsumerExecutionContext context) { _logger.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 = _policy.Execute(() => { var task = context.UserHandler(context.Body, context.Properties, context.Info); if (task.IsFaulted) { throw task.Exception.GetBaseException(); } return(task); }); } catch (Exception exception) { completionTask = TaskHelpers.FromException(exception); } if (completionTask.Status == TaskStatus.Created) { _logger.ErrorWrite("Task returned from consumer callback is not started. ConsumerTag: '{0}'", context.Info.ConsumerTag); return; } completionTask.ContinueWith(task => base.DoAck(context, base.GetAckStrategy(context, task))); }
public void HandleBasicDeliver( string consumerTag, ulong deliveryTag, bool redelivered, string exchange, string routingKey, IBasicProperties properties, byte[] body) { logger.DebugWrite("HandleBasicDeliver on consumer: {0}, deliveryTag: {1}", consumerTag, deliveryTag); if (disposed) { // this message's consumer has stopped, so just return logger.InfoWrite("Consumer has stopped running. Consumer '{0}' on queue '{1}'. Ignoring message", ConsumerTag, queue.Name); return; } if (onMessage == null) { logger.ErrorWrite("User consumer callback, 'onMessage' has not been set for consumer '{0}'." + "Please call InternalConsumer.StartConsuming before passing the consumer to basic.consume", ConsumerTag); return; } var messageReceivedInfo = new MessageReceivedInfo(consumerTag, deliveryTag, redelivered, exchange, routingKey, queue.Name); var messsageProperties = new MessageProperties(properties); var context = new ConsumerExecutionContext(onMessage, messageReceivedInfo, messsageProperties, body, this); consumerDispatcher.QueueAction(() => handlerRunner.InvokeUserMessageHandler(context)); }
public void InvokeUserMessageHandler(ConsumerExecutionContext context) { Preconditions.CheckNotNull(context, "context"); logger.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.UserHandler(context.Body, context.Properties, context.Info); } catch (Exception exception) { completionTask = TaskHelpers.FromException(exception); } if (completionTask.Status == TaskStatus.Created) { logger.ErrorWrite("Task returned from consumer callback is not started. ConsumerTag: '{0}'", context.Info.ConsumerTag); return; } completionTask.ContinueWith(task => DoAck(context, GetAckStrategy(context, task))); }
private void HandleMessageDelivery(BasicDeliverEventArgs basicDeliverEventArgs) { var consumerTag = basicDeliverEventArgs.ConsumerTag; if (!subscriptions.ContainsKey(consumerTag)) { throw new EasyNetQException("No callback found for ConsumerTag {0}", consumerTag); } logger.DebugWrite("Subscriber Recieved {0}, CorrelationId {1}", basicDeliverEventArgs.RoutingKey, basicDeliverEventArgs.BasicProperties.CorrelationId); var subscriptionInfo = subscriptions[consumerTag]; try { var completionTask = subscriptionInfo.Callback( consumerTag, basicDeliverEventArgs.DeliveryTag, basicDeliverEventArgs.Redelivered, basicDeliverEventArgs.Exchange, basicDeliverEventArgs.RoutingKey, basicDeliverEventArgs.BasicProperties, basicDeliverEventArgs.Body); completionTask.ContinueWith(task => { if (task.IsFaulted) { var exception = task.Exception; logger.ErrorWrite(BuildErrorMessage(basicDeliverEventArgs, exception)); consumerErrorStrategy.HandleConsumerError(basicDeliverEventArgs, exception); } DoAck(basicDeliverEventArgs, subscriptionInfo); }); } catch (Exception exception) { logger.ErrorWrite(BuildErrorMessage(basicDeliverEventArgs, exception)); consumerErrorStrategy.HandleConsumerError(basicDeliverEventArgs, exception); DoAck(basicDeliverEventArgs, subscriptionInfo); } }
public void RawPublish(string exchangeName, string topic, string typeName, byte[] messageBody, byte priority) { if (!connection.IsConnected) { throw new EasyNetQException("Publish failed. No rabbit server connected."); } try { if (!threadLocalPublishChannel.IsValueCreated) { threadLocalPublishChannel.Value = connection.CreateModel(); modelList.Add(threadLocalPublishChannel.Value); } DeclarePublishExchange(threadLocalPublishChannel.Value, exchangeName); var defaultProperties = threadLocalPublishChannel.Value.CreateBasicProperties(); defaultProperties.SetPersistent(false); defaultProperties.Type = typeName; defaultProperties.CorrelationId = getCorrelationId(); defaultProperties.Priority = priority; threadLocalPublishChannel.Value.BasicPublish( exchangeName, // exchange topic, // routingKey defaultProperties, // basicProperties messageBody); // body logger.DebugWrite("Published {0}, CorrelationId {1}", exchangeName, defaultProperties.CorrelationId); } catch (OperationInterruptedException exception) { throw new EasyNetQException("Publish Failed: '{0}'", exception.Message); } catch (System.IO.IOException exception) { throw new EasyNetQException("Publish Failed: '{0}'", exception.Message); } }
public void Start() { log.DebugWrite("Starting SchedulerService"); bus.Subscribe <ScheduleMe>(configuration.SubscriptionId, OnMessage); bus.Subscribe <UnscheduleMe>(configuration.SubscriptionId, OnMessage); publishTimer = new Timer(OnPublishTimerTick, null, TimeSpan.Zero, configuration.PublishInterval); handleTimeoutTimer = new Timer(OnHandleTimeoutTimerTick, null, TimeSpan.Zero, configuration.HandleTimeoutInterval); }
public void InvokeUserMessageHandler(ConsumerExecutionContext context) { Preconditions.CheckNotNull(context, "context"); logger.DebugWrite("Recieved \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); try { var completionTask = context.UserHandler(context.Body, context.Properties, context.Info); if (completionTask.Status == TaskStatus.Created) { logger.ErrorWrite("Task returned from consumer callback is not started. ConsumerTag: '{0}'", context.Info.ConsumerTag); } else { completionTask.ContinueWith(task => { if (task.IsFaulted) { var exception = task.Exception; HandleErrorInSubscriptionHandler(context, exception); } else { DoAck(context, SuccessAckStrategy); } }); } } catch (Exception exception) { HandleErrorInSubscriptionHandler(context, exception); } }
public void ExecuteAction(bool isNewConnection) { try { Action(isNewConnection); } catch (OperationInterruptedException operationInterruptedException) { logger.ErrorWrite("Failed to create subscribers: reason: '{0}'\n{1}", operationInterruptedException.Message, operationInterruptedException.ToString()); } catch (EasyNetQException exc) { // and the subscription action." // Looks like the channel closed between our IsConnected check // and the subscription action. Do nothing here, when the // connection comes back, the subscription action will be run then. logger.DebugWrite("Channel closed between our IsConnected check.", exc); } }
// -------------------------------- publish --------------------------------------------- public void Publish( IExchange exchange, string routingKey, bool mandatory, MessageProperties messageProperties, byte[] body) { // Fix me: It's very hard now to move publish logic to separate abstraction, just leave it here. var rawMessage = produceConsumeInterceptor.OnProduce(new RawMessage(messageProperties, body)); if (connectionConfiguration.PublisherConfirms) { var timeBudget = new TimeBudget(TimeSpan.FromSeconds(connectionConfiguration.Timeout)).Start(); while (!timeBudget.IsExpired()) { var confirmsWaiter = clientCommandDispatcher.Invoke(model => { var properties = model.CreateBasicProperties(); rawMessage.Properties.CopyTo(properties); var waiter = confirmationListener.GetWaiter(model); try { model.BasicPublish(exchange.Name, routingKey, mandatory, properties, rawMessage.Body); } catch (Exception) { waiter.Cancel(); throw; } return(waiter); }); try { confirmsWaiter.Wait(timeBudget.GetRemainingTime()); break; } catch (PublishInterruptedException) { } } } else { clientCommandDispatcher.Invoke(model => { var properties = model.CreateBasicProperties(); rawMessage.Properties.CopyTo(properties); model.BasicPublish(exchange.Name, routingKey, mandatory, properties, rawMessage.Body); }); } eventBus.Publish(new PublishedMessageEvent(exchange.Name, routingKey, rawMessage.Properties, rawMessage.Body)); logger.DebugWrite("Published to exchange: '{0}', routing key: '{1}', correlationId: '{2}'", exchange.Name, routingKey, messageProperties.CorrelationId); }
/// <summary> /// This method is fired when an exception is thrown. Implement a strategy for /// handling the exception here. /// </summary> /// <param name="context">The consumer execution context.</param> /// <param name="exception">The exception</param> /// <returns><see cref="AckStrategy"/> for processing the original failed message</returns> public AckStrategy HandleConsumerError(ConsumerExecutionContext context, Exception exception) { try { // First write the exception to the logger _logger.ErrorWrite(exception); Connect(); using (var model = _connection.CreateModel()) { var properties = context.Properties; var flrRetry = 1; if (properties.HeadersPresent && properties.Headers.ContainsKey("easynetq.retry.count")) { flrRetry = Convert.ToInt16(properties.Headers["easynetq.retry.count"]) + 1; } // Max retries set to 2 means we will run it once more, 3 means run it twice more, 3 etc etc if (flrRetry < _flrMaxRetries) { _logger.InfoWrite( $"(FLR) First Level Retry [{flrRetry}] for message of type [{properties.Type}]."); RetryMessage(context, model, properties, flrRetry); _logger.DebugWrite("Message resent."); } else { _logger.DebugWrite( $"Reached maximum First Level Retry, handing over to dead letter queue, message of type [{properties.Type}]."); // Send message to the deadletter queue SendMessageToErrorQueue(context, exception, model, properties); } } } catch (BrokerUnreachableException) { // thrown if the broker is unreachable during initial creation. _logger.ErrorWrite("EasyNetQ Consumer Error Handler cannot connect to Broker\n" + CreateConnectionCheckMessage()); } catch (OperationInterruptedException interruptedException) { // thrown if the broker connection is broken during declare or publish. _logger.ErrorWrite("EasyNetQ Consumer Error Handler: Broker connection was closed while attempting to publish Error message.\n" + $"Message was: '{interruptedException.Message}'\n" + CreateConnectionCheckMessage()); } catch (Exception unexpectedException) { // Something else unexpected has gone wrong :( _logger.ErrorWrite("EasyNetQ Consumer Error Handler: Failed to publish error message\nException is:\n" + unexpectedException); } return(AckStrategies.Ack); }
// -------------------------------- publish --------------------------------------------- public virtual Task PublishAsync( IExchange exchange, string routingKey, bool mandatory, bool immediate, MessageProperties messageProperties, byte[] body) { Preconditions.CheckNotNull(exchange, "exchange"); Preconditions.CheckShortString(routingKey, "routingKey"); Preconditions.CheckNotNull(messageProperties, "messageProperties"); Preconditions.CheckNotNull(body, "body"); var rawMessage = produceConsumeInterceptor.OnProduce(new RawMessage(messageProperties, body)); return(clientCommandDispatcher.Invoke(x => { var properties = x.CreateBasicProperties(); rawMessage.Properties.CopyTo(properties); return publisher.Publish(x, m => m.BasicPublish(exchange.Name, routingKey, mandatory, immediate, properties, rawMessage.Body)) .Then(() => { eventBus.Publish(new PublishedMessageEvent(exchange.Name, routingKey, rawMessage.Properties, rawMessage.Body)); logger.DebugWrite("Published to exchange: '{0}', routing key: '{1}', correlationId: '{2}'", exchange.Name, routingKey, messageProperties.CorrelationId); }); }).Unwrap()); }
// -------------------------------- publish --------------------------------------------- public virtual Task PublishAsync( IExchange exchange, string routingKey, bool mandatory, bool immediate, MessageProperties messageProperties, byte[] body) { Preconditions.CheckNotNull(exchange, "exchange"); Preconditions.CheckShortString(routingKey, "routingKey"); Preconditions.CheckNotNull(messageProperties, "messageProperties"); Preconditions.CheckNotNull(body, "body"); var task = clientCommandDispatcher.Invoke(x => { var properties = x.CreateBasicProperties(); messageProperties.CopyTo(properties); return(publisherConfirms.PublishWithConfirm(x, m => m.BasicPublish(exchange.Name, routingKey, mandatory, immediate, properties, body))); }).Unwrap(); logger.DebugWrite("Published to exchange: '{0}', routing key: '{1}', correlationId: '{2}'", exchange.Name, routingKey, messageProperties.CorrelationId); return(task); }
public void Start() { log.DebugWrite("Starting PublisherService"); bus.Subscribe <ScheduleMe>(schedulerSubscriptionId, Evaluate); }
public void OnMessage(ScheduleMe scheduleMe) { log.DebugWrite("Got Schedule Message"); scheduleRepository.Store(scheduleMe); }
public virtual void Consume(IQueue queue, Func <Byte[], MessageProperties, MessageReceivedInfo, Task> onMessage) { Preconditions.CheckNotNull(queue, "queue"); Preconditions.CheckNotNull(onMessage, "onMessage"); if (disposed) { throw new EasyNetQException("This bus has been disposed"); } var newConsumerTag = conventions.ConsumerTagConvention(); var subscriptionAction = new SubscriptionAction(newConsumerTag, logger, queue.IsSingleUse, queue.IsExclusive); subscriptionAction.Action = (isNewConnection) => { // recreate channel if current channel is no longer open or connection was dropped and reconnected (to survive server restart) if (subscriptionAction.Channel == null || subscriptionAction.Channel.IsOpen == false || isNewConnection) { subscriptionAction.Channel = CreateChannel(queue); } var channel = subscriptionAction.Channel; channel.BasicQos(0, connectionConfiguration.PrefetchCount, false); var consumer = consumerFactory.CreateConsumer(subscriptionAction, channel, queue.IsSingleUse, (consumerTag, deliveryTag, redelivered, exchange, routingKey, properties, body) => { var messageRecievedInfo = new MessageReceivedInfo { ConsumerTag = consumerTag, DeliverTag = deliveryTag, Redelivered = redelivered, Exchange = exchange, RoutingKey = routingKey }; var messsageProperties = new MessageProperties(properties); return(onMessage(body, messsageProperties, messageRecievedInfo)); }); var cancelNotifications = consumer as IConsumerCancelNotifications; if (cancelNotifications != null) { cancelNotifications.BasicCancel += OnBasicCancel; } channel.BasicConsume( queue.Name, // queue NoAck, // noAck consumer.ConsumerTag, // consumerTag consumer); // consumer logger.DebugWrite("Declared Consumer. queue='{0}', consumer tag='{1}' prefetchcount={2}", queue.Name, consumer.ConsumerTag, connectionConfiguration.PrefetchCount); }; AddSubscriptionAction(subscriptionAction); }
// ---------------------------------- Exchange / Queue / Binding ----------------------------------- public IQueue QueueDeclare( string name, bool passive = false, bool durable = true, bool exclusive = false, bool autoDelete = false, uint perQueueTtl = UInt32.MaxValue, uint expires = UInt32.MaxValue) { Preconditions.CheckNotNull(name, "name"); using (var model = connection.CreateModel()) { IDictionary <string, object> arguments = new Dictionary <string, object>(); if (passive) { model.QueueDeclarePassive(name); } else { if (perQueueTtl != uint.MaxValue) { arguments.Add("x-message-ttl", perQueueTtl); } if (expires != uint.MaxValue) { arguments.Add("x-expires", expires); } model.QueueDeclare(name, durable, exclusive, autoDelete, (IDictionary)arguments); logger.DebugWrite("Declared Queue: '{0}' durable:{1}, exclusive:{2}, autoDelte:{3}, args:{4}", name, durable, exclusive, autoDelete, WriteArguments(arguments)); } return(new Topology.Queue(name, exclusive)); } }
public void Dispose() { CloseChannel(); logger.DebugWrite("Persistent internalChannel disposed."); }