Example #1
0
    public Task PublishAsync <TEvent>(TEvent @event) where TEvent : EventBase
    {
        Check.NotNull(@event, nameof(@event));

        if (!_connection.IsConnected)
        {
            _connection.TryConnect();
        }

        var policy = Policy.Handle <BrokerUnreachableException>()
                     .Or <SocketException>()
                     .WaitAndRetry(_options.RetryCount, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)),
                                   (ex, time) =>
        {
            _logger.LogWarning(ex,
                               $"Could not publish event: {@event.EventId} after {time.TotalSeconds:n1}s ({ex.Message})");
        });

        IModel channel = null;

        try
        {
            var eventName = @event.GetType().GetEventName();
            var bytes     = Encoding.UTF8.GetBytes(Default.JsonHelper.Serialize(@event));

            policy.Execute(() =>
            {
                if (channel == null)
                {
                    channel = _connection.CreateModel();
                    _logger.LogTrace($"Declaring RabbitMQ exchange to publish event: {@event.EventId}");

                    channel.ExchangeDeclare(_options.Exchange, "direct");
                }

                var properties          = channel.CreateBasicProperties();
                properties.DeliveryMode = 2; // persistent

                _logger.LogTrace($"Publishing event to RabbitMQ: {@event.EventId}");

                channel.BasicPublish(_options.Exchange, eventName, true, properties, bytes);
                channel.Dispose();
            });
        }
        finally
        {
            // channel.Close();
            channel?.Dispose();
        }

        return(Task.CompletedTask);
    }
        public override async ValueTask Publish(IIntegrationEvent @event)
        {
            if (!PersistentConnection.IsConnected)
            {
                PersistentConnection.TryConnect();
            }

            var policy = Policy.Handle <BrokerUnreachableException>()
                         .Or <SocketException>()
                         .Or <Exception>()
                         .WaitAndRetryForever(retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)), (ex, time) =>
            {
                Logger.LogWarning(ex.ToString());
            });

            using var channel = PersistentConnection.CreateModel();
            var routingKey = @event.RoutingKey;

            channel.ExchangeDeclare(ExchangeDeclareParameters.ExchangeName, ExchangeDeclareParameters.ExchangeType, ExchangeDeclareParameters.ExchangeDurable, ExchangeDeclareParameters.ExchangeAutoDelete);

            await using var ms = new MemoryStream();
            Serializer.Serialize(ms, @event);
            var body = ms.ToArray();

            policy.Execute(() =>
            {
                var properties           = channel.CreateBasicProperties();
                properties.DeliveryMode  = 1; //2 = persistent, write on disk
                properties.CorrelationId = _correlationId;
                properties.ReplyTo       = _queueNameReply;
                channel.BasicPublish(ExchangeDeclareParameters.ExchangeName, routingKey, true, properties, body);
            });
        }
Example #3
0
        private void SubsManager_OnEventReplyRemoved(object sender, string eventName)
        {
            if (!PersistentConnection.IsConnected)
            {
                PersistentConnection.TryConnect();
            }

            using (var channel = PersistentConnection.CreateModel())
            {
                channel.QueueUnbind(QueueName, ExchangeDeclareParameters.ExchangeName, eventName);

                channel.QueueUnbind(_queueNameReply, ExchangeDeclareParameters.ExchangeName, eventName);
            }

            if (!SubsManager.IsReplyEmpty)
            {
                return;
            }

            QueueName = string.Empty;
            ConsumerChannel?.Close();

            //ToDo

            _queueNameReply = string.Empty;
            _consumerChannelReply?.Close();
        }
        /// <summary>
        /// Do a passive exchange declaration.
        /// Or
        /// (Spec method) Declare an exchange.
        ///  This method performs a "passive declare" on an exchange, which verifies whether. It will do nothing if the exchange already exists and result in a channel-levelprotocol exception (channel closure) if not.
        /// </summary>
        /// <param name="persistentConnection"></param>
        /// <param name="exchange"></param>
        /// <param name="type"></param>
        /// <param name="durable"></param>
        /// <param name="autoDelete"></param>
        /// <param name="arguments"></param>
        public static IModel ExchangeDeclare(this PersistentConnection persistentConnection, string exchange, string type = ExchangeType.Topic, bool durable = true, bool autoDelete = false, IDictionary <string, object> arguments = null)
        {
            IModel channel;

            try
            {
                channel = persistentConnection.CreateModel();
                channel.ExchangeDeclarePassive(exchange);
            }
            catch
            {
                channel = persistentConnection.CreateModel();
                channel.ExchangeDeclare(exchange, type, durable, autoDelete, arguments);
            }

            return(channel);
        }
        public void Should_establish_connection_when_persistent_connection_created()
        {
            var mockBuilder = new MockBuilder();

            using var connection = new PersistentConnection(
                      new ConnectionConfiguration(), mockBuilder.ConnectionFactory, mockBuilder.EventBus
                      );

            connection.CreateModel();

            connection.IsConnected.Should().BeTrue();
            mockBuilder.ConnectionFactory.Received(1).CreateConnection(Arg.Any <IList <AmqpTcpEndpoint> >());
        }
        public void Should_be_not_connected_if_connection_not_established()
        {
            var mockBuilder = new MockBuilder();

            mockBuilder.ConnectionFactory.CreateConnection(Arg.Any <IList <AmqpTcpEndpoint> >())
            .Returns(c => throw new Exception("Test"));

            using var connection = new PersistentConnection(
                      new ConnectionConfiguration(), mockBuilder.ConnectionFactory, mockBuilder.EventBus
                      );

            Assert.Throws <Exception>(() => connection.CreateModel());

            connection.IsConnected.Should().BeFalse();
            mockBuilder.ConnectionFactory.Received().CreateConnection(Arg.Any <IList <AmqpTcpEndpoint> >());
        }
        private void DoInternalSubscriptionRpc(string eventName, string eventNameResult)
        {
            var containsKey = SubsManager.HasSubscriptionsForEvent(eventName);

            if (containsKey)
            {
                return;
            }
            if (!PersistentConnection.IsConnected)
            {
                PersistentConnection.TryConnect();
            }

            using var channel = PersistentConnection.CreateModel();
            channel.QueueBind(QueueName, ExchangeDeclareParameters.ExchangeName, eventName);
            channel.QueueBind(_queueNameReply, ExchangeDeclareParameters.ExchangeName, eventNameResult);
        }
Example #8
0
        public async Task <TR> CallAsync <TR>(IIntegrationEvent @event, CancellationToken cancellationToken = default)
            where TR : IIntegrationEventReply
        {
            if (!PersistentConnection.IsConnected)
            {
                PersistentConnection.TryConnect();
            }

            var policy = Policy.Handle <BrokerUnreachableException>()
                         .Or <SocketException>()
                         .Or <Exception>()
                         .WaitAndRetryForever(retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)), (ex, time) =>
            {
                Logger.LogWarning(ex.ToString());
            });

            using var channel = PersistentConnection.CreateModel();
            var routingKey = @event.RoutingKey;

            channel.ExchangeDeclare(ExchangeDeclareParameters.ExchangeName, ExchangeDeclareParameters.ExchangeType, ExchangeDeclareParameters.ExchangeDurable, ExchangeDeclareParameters.ExchangeAutoDelete);

            await using var ms = new MemoryStream();
            Serializer.Serialize(ms, @event);
            var body          = ms.ToArray();
            var correlationId = Guid.NewGuid().ToString();
            var tcs           = new TaskCompletionSource <dynamic>();

            _callbackMapper.TryAdd(correlationId, tcs);

            policy.Execute(() =>
            {
                var properties           = channel.CreateBasicProperties();
                properties.DeliveryMode  = 1; //2 = persistent, write on disk
                properties.CorrelationId = correlationId;
                properties.ReplyTo       = QueueName;
                channel.BasicPublish(ExchangeDeclareParameters.ExchangeName, routingKey, true, properties, body);
            });

            cancellationToken.Register(() => _callbackMapper.TryRemove(correlationId, out var tmp));
            return(await tcs.Task);
        }
        private IModel CreateConsumerChannelReply(CancellationToken cancel = default)
        {
            if (!PersistentConnection.IsConnected)
            {
                PersistentConnection.TryConnect();
            }

            var channel = PersistentConnection.CreateModel();

            channel.ExchangeDeclare(ExchangeDeclareParameters.ExchangeName, ExchangeDeclareParameters.ExchangeType, ExchangeDeclareParameters.ExchangeDurable, ExchangeDeclareParameters.ExchangeAutoDelete);

            channel.QueueDeclare(_queueNameReply, QueueDeclareParameters.QueueDurable, QueueDeclareParameters.QueueExclusive, QueueDeclareParameters.QueueAutoDelete, null);
            channel.BasicQos(0, 1, false);

            channel.CallbackException += (sender, ea) =>
            {
                Logger.LogError("CallbackException Rpc: " + ea.Exception.Message);
                _consumerChannelReply.Dispose();
                _consumerChannelReply = CreateConsumerChannelReply(cancel);
                StartBasicConsumeReply();
            };

            return(channel);
        }
 /// <summary>
 ///
 /// </summary>
 /// <param name="persistentConnection"></param>
 /// <returns></returns>
 public static IModel Channel(this PersistentConnection persistentConnection)
 => persistentConnection.CreateModel();
        public async Task <TIntegrationEventReply> CallAsync <TIntegrationEventReply>(IIntegrationEvent @event, CancellationToken cancellationToken = default)
            where TIntegrationEventReply : IIntegrationEventReply
        {
            try
            {
                if (!PersistentConnection.IsConnected)
                {
                    PersistentConnection.TryConnect();
                }

                var policy = Policy.Handle <BrokerUnreachableException>()
                             .Or <SocketException>()
                             .Or <Exception>()
                             .WaitAndRetryForever(retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)), (ex, time) =>
                {
                    Logger.LogWarning(ex.ToString());
                });

                var correlationId = Guid.NewGuid().ToString();

                var tcs = new TaskCompletionSource <dynamic>(TaskCreationOptions.RunContinuationsAsynchronously);
                _callbackMapper.TryAdd(correlationId, tcs);

                using (var channel = PersistentConnection.CreateModel())
                {
                    var routingKey = @event.RoutingKey;

                    channel.ExchangeDeclare(ExchangeDeclareParameters.ExchangeName,
                                            ExchangeDeclareParameters.ExchangeType,
                                            ExchangeDeclareParameters.ExchangeDurable, ExchangeDeclareParameters.ExchangeAutoDelete);

                    await using var ms = new MemoryStream();

                    Serializer.Serialize(ms, @event);
                    var body = ms.ToArray();

                    policy.Execute(() =>
                    {
                        var properties = channel.CreateBasicProperties();
                        //properties.ContentType = "application/protobuf";
                        properties.DeliveryMode  = 1; //2 = persistent, write on disk
                        properties.CorrelationId = correlationId;
                        //properties.ReplyTo = QueueName;
                        properties.ReplyTo = _queueNameReply; //ToDo

                        channel.BasicPublish(ExchangeDeclareParameters.ExchangeName, routingKey, true, properties,
                                             body);
                    });
                }

                cancellationToken.Register(() => _callbackMapper.TryRemove(correlationId, out var tmp));

                var result = await tcs.Task.ConfigureAwait(false);

                return((TIntegrationEventReply)result);
            }
            catch (Exception ex)
            {
                Logger.LogError("CallAsync: " + ex.Message + " " + ex.StackTrace);
            }
            return(default);