Beispiel #1
0
        public Task StartSubscriptionAsync(ISubscription subscription, CancellationToken cancellationToken)
        {
            return(Task.Run(async() =>
            {
                _logger.LogInformation($"Start Subscription ...[{subscription.Identifier}]");


                //Cancellation Actions
                cancellationToken.Register(() =>
                {
                    _logger.LogInformation(
                        $"Cancellation Token Requested for Subscription : [{subscription.Identifier}]");
                });

                if (subscription.IsRunning)
                {
                    _logger.LogWarning($"The Subscription [{subscription.Identifier}] is in Running mode - cannot run again");
                    return;
                }

                //subscription.IsRunning = true;

                while (!cancellationToken.IsCancellationRequested)
                {
                    try
                    {
                        using (var connection = _queueClient.Factory.CreateConnection())
                            using (var channel = connection.CreateModel())
                            {
                                // Declare the exchange, the queue and bind them together.
                                channel.ExchangeDeclare(subscription.Exchange, "topic", true);
                                QueueDeclareOk queueDeclare = null;


                                if (!_queueClient.Options.DisableDeadLettering)
                                {
                                    var deadLetterExchange =
                                        subscription.Exchange + _queueClient.Options.DeadLetterPostFix;
                                    var deadLetterQueue = subscription.Queue + _queueClient.Options.DeadLetterPostFix;

                                    // Create the queue and set the bindings to the dead letter exchange
                                    IDictionary <String, Object> args = new Dictionary <String, Object>();
                                    args.Add("x-dead-letter-exchange", deadLetterExchange);
                                    args.Add("x-dead-letter-routing-key", deadLetterQueue);

                                    queueDeclare = channel.QueueDeclare(subscription.Queue, true, false, false, args);


                                    // create the dead letter queue and bind it ignoring routing keys. Catch all.
                                    channel.QueueDeclare(deadLetterQueue, true, false, false, null);
                                    channel.QueueBind(deadLetterQueue, deadLetterExchange, deadLetterQueue);
                                }
                                else
                                {
                                    queueDeclare = channel.QueueDeclare(subscription.Queue, true, false, false, null);
                                }



                                using (var passiveChannel = connection.CreateModel())
                                {
                                    try
                                    {
                                        passiveChannel.ExchangeDeclarePassive(subscription.Exchange);
                                        passiveChannel.QueueDeclarePassive(subscription.Queue);
                                        passiveChannel.Close();
                                    }
                                    catch (Exception ex)
                                    {
                                        _logger.LogError(ex, "Exchange or Queue dose not exist");
                                        passiveChannel.Close();
                                        connection.Close();
                                        break;
                                    }
                                }


                                //Bind to Queue

                                channel.QueueBind(subscription.Queue, subscription.Exchange, subscription.EventType);



                                var consumer = new AsyncEventingBasicConsumer(channel);

                                _logger.LogInformation($"Start Listening ...[{subscription.Identifier}]");

                                consumer.Received += async(model, ea) =>
                                {
                                    var body = ea.Body;
                                    var rawMessage = Encoding.UTF8.GetString(body);
                                    _logger.LogInformation($"Message Received : [{rawMessage}]");

                                    Message messageObj = null;
                                    messageObj = ParseMessage(rawMessage);

                                    using (var scope = _serviceProvider.CreateScope())
                                    {
                                        var processor =
                                            (IMessageProcessor)scope.ServiceProvider.GetRequiredService(
                                                subscription
                                                .ProcessorType);
                                        IMessageControlService messageControlSrv =
                                            scope.ServiceProvider.GetService <IMessageControlService>();

                                        try
                                        {
                                            // Let the MessageController know know we got a message.
                                            messageControlSrv?.SendMessageControl(MessageState.Received, messageObj, subscription);

                                            var result = await processor.ProcessAsync(messageObj);

                                            switch (result.Status)
                                            {
                                            case ResultStatus.Success:

                                                channel.BasicAck(ea.DeliveryTag, false);
                                                // Let the MessageController know we have a failure.
                                                messageControlSrv?.SendMessageControl(MessageState.Success, messageObj, subscription, result.Response);

                                                break;

                                            case ResultStatus.Retry:

                                                _logger.LogWarning(
                                                    $"SubscriptionID: {subscription.Identifier} - Returned Retry from Processor for MessageID: {messageObj.MessageID}");

                                                channel.BasicNack(ea.DeliveryTag, false, false);
                                                messageControlSrv?.SendMessageControl(MessageState.Retry, messageObj, subscription, result.Response);

                                                break;

                                            case ResultStatus.Failure:

                                                _logger.LogWarning(
                                                    $"SubscriptionID: {subscription.Identifier} - Returned Failure from Processor for MessageID: {messageObj.MessageID}");

                                                channel.BasicNack(ea.DeliveryTag, false, false);
                                                messageControlSrv?.SendMessageControl(MessageState.Failure, messageObj, subscription, result.Response);

                                                break;
                                            }
                                        }
                                        catch (Exception ex)
                                        {
                                            _logger.LogError(ex,
                                                             $"SubscriptionId: [{subscription.Identifier}] - Error reported from messageTarget for MessageID: [{messageObj?.MessageID}]");

                                            channel.BasicNack(ea.DeliveryTag, false, false);
                                            messageControlSrv?.SendMessageControl(MessageState.Failure, messageObj, subscription, ex);
                                        }
                                    }
                                };

                                channel.BasicConsume(queue: queueDeclare.QueueName,
                                                     autoAck: false,
                                                     consumer: consumer);

                                subscription.IsRunning = true;


                                await Task.WhenAny(Task.Delay(Timeout.Infinite, cancellationToken));
                            }
                    }
                    catch (EndOfStreamException ex)
                    {
                        _logger.LogError(ex,
                                         $"SubscriptionID: {subscription.Identifier} - An EndOfStreamException occurred with the rabbit queue process. We will not recover, and remove the subscriptions.");
                        break;
                    }
                    catch (RabbitMQ.Client.Exceptions.BrokerUnreachableException ex)
                    {
                        _logger.LogError(ex,
                                         $"SubscriptionID: {subscription.Identifier} - An IOException occurred with the rabbit queue process. We will attempt to recover in {_queueClient.Options.SystemRecoveryInterval} seconds.");
                        await Task.Delay(_queueClient.Options.SystemRecoveryInterval * 1000, cancellationToken);
                    }
                    catch (IOException ex)
                    {
                        _logger.LogError(ex,
                                         $"SubscriptionID: {subscription.Identifier} - An IOException occurred with the rabbit queue process. We will attempt to recover in {_queueClient.Options.SystemRecoveryInterval} seconds.");
                        await Task.Delay(_queueClient.Options.SystemRecoveryInterval * 1000, cancellationToken);
                    }
                }



                _logger.LogInformation($"Stop Subscription [{subscription.Identifier}]...");
            }));
        }
 public Publisher(ILogger <Publisher> logger, IQueueClient queueClient, IMessageControlService messageControlService)
 {
     _logger                = logger;
     _queueClient           = queueClient;
     _messageControlService = messageControlService;
 }