Esempio n. 1
0
 public MessageBrokerConfigBuilder()
 {
     Config = new MessageBrokerConsumerConfig();
 }
        public async Task <Action> Subscribe(string topic,
                                             string subscriptionId,
                                             Func <object, Task> onReceive,
                                             Type eventModelType,
                                             Func <MessageBrokerConfigBuilder, MessageBrokerConfigBuilder> config = null)
        {
            var brokerConfig = new MessageBrokerConsumerConfig();

            if (config != null)
            {
                var configBuilder = config.Invoke(new MessageBrokerConfigBuilder());
                brokerConfig = configBuilder.Config;
            }

            var channel = await GetChannel(topic, subscriptionId);

            channel.ExchangeDeclare(topic,
                                    "topic",
                                    durable: true
                                    );

            var queueName = $"{topic}_{subscriptionId}";

            channel.QueueDeclare(queueName,
                                 durable: true,
                                 exclusive: false,
                                 autoDelete: false
                                 );

            if (brokerConfig.UseBasicQos)
            {
                channel.BasicQos(0, brokerConfig.BasicQosPrefetch, false);
            }

            channel.QueueBind(
                queueName,
                topic,
                ""
                );

            IMessageBrokerDefaultLogger logger;

            logger = new MessageBrokerDefaultLogger(_logger);
            if (brokerConfig.SubscriptionLogger != null)
            {
                logger = brokerConfig.SubscriptionLogger;
            }

            var consumer = new EventingBasicConsumer(channel);

            consumer.Received += (model, basicAckEventArgs) =>
            {
                var sw = new Stopwatch();
                sw.Start();
                var body          = Encoding.UTF8.GetString(basicAckEventArgs.Body);
                var instanceModel = new
                {
                    body,
                    DateTime.UtcNow,
                    basicAckEventArgs.ConsumerTag
                };

                var instanceModelJson = JsonConvert.SerializeObject(instanceModel);
                var instanceHash      = instanceModelJson.ToMd5Hash();
                var eventModel        = JsonConvert.DeserializeObject(body, eventModelType);
                var logContext        = new MessageReceivedLogContext
                {
                    CorrelationId  = instanceHash,
                    SubscriptionId = subscriptionId,
                    Topic          = topic
                };

                logger.MessageReceived(eventModel, logContext, sw.ElapsedMilliseconds);
                sw.Restart();
                try
                {
                    onReceive(eventModel).Wait();

                    logger.ProcessingSucceeded(eventModel, logContext, sw.ElapsedMilliseconds);
                }
                catch (Exception exception)
                {
                    logger.ProcessingFailed(eventModel, logContext, exception, sw.ElapsedMilliseconds);
                    sw.Restart();
                }
            };

            channel.BasicConsume(queueName, true, consumer);

            EventHandler <ShutdownEventArgs> onDisconnect = null;

            onDisconnect = async(sender, args) =>
            {
                channel.ModelShutdown -= onDisconnect;
                if (channel.IsClosed &&
                    channel.CloseReason.ReplyCode == 0 &&
                    channel.CloseReason.ReplyText == "Shutdown")
                {
                    return;
                }

                _defaultLogger.ConnectionLostReconnecting(topic, subscriptionId);
                await Subscribe(topic, subscriptionId, onReceive);
            };

            channel.ModelShutdown += onDisconnect;

            _defaultLogger.SubedAndCompeting(topic, subscriptionId);

            return(() =>
            {
                channel.Close(0, "Shutdown");
                _defaultLogger.UnsubFromTopic(topic, subscriptionId);
            });
        }