Esempio n. 1
0
        private void ConnectToExchange()
        {
            var args = new Dictionary <string, object>();

            if (ChannelParameters.Ttl != -1)
            {
                args.Add(DictionaryKey_QueueTtl, ChannelParameters.Ttl);
            }

            var element = $"exchange {ExchangeName}";

            try
            {
                Channel.ExchangeDeclare(ExchangeName, ExchangeType, ChannelParameters.Durable, ChannelParameters.AutoDelete);
                element = $"queue {QueueName}";
                Channel.QueueDeclare(QueueName, ChannelParameters.Durable, false, ChannelParameters.AutoDelete, args);
            }

            catch (OperationInterruptedException oie)
            {
                var e = new ChannelOpenFailureException($"Unable to create the {EndpointType} {element}: " + oie.Message, oie);
                VerboseLoggingHandler.Log(e);
                throw e;
            }

            Channel.BasicAcks         += ChannelOnBasicAcks;
            Channel.BasicNacks        += ChannelOnBasicNacks;
            Channel.BasicReturn       += ChannelOnBasicReturn;
            Channel.ModelShutdown     += ChannelOnModelShutdown;
            Channel.CallbackException += ChannelOnCallbackException;
        }
Esempio n. 2
0
        public async Task <bool> Ping(string routingKeyOrTopicName = "", IDictionary <string, object> headers = null, MessageParameters mp = null)
        {
            VerboseLoggingHandler.Log($"Sending Hello ping");
            var response = await SendMessageInternal(routingKeyOrTopicName, ConvertStringToMessage(MessageContent_Ping), headers, MessageType.RequireAck, mp);

            return(response != null && ConvertMessageToString(response) == MessageContent_PingResponse);
        }
        private async Task RpcReturnChannelConsumerOnReceivedAsync(object sender, BasicDeliverEventArgs ea)
        {
            await Task.Delay(0);

            VerboseLoggingHandler.Log($"Event RpcReturnChannelConsumerOnReceivedAsync triggered Exchange='{ea.Exchange}', routingKeyOrTopicName='{ea.RoutingKey}', replyText='{ea.DeliveryTag}', consumerTag='{ea.ConsumerTag}'");
            ReturnData = ea.Body.ToArray();
            ReturnChannelLatch.Release(1);
        }
 public void Listen()
 {
     if (EndpointType != EndpointTypeEnum.Consumer)
     {
         var e = new InvalidOperationException("Attempt to listen on a non-consumer prohibited.");
         VerboseLoggingHandler.Log(e);
         throw e;
     }
     Channel.BasicConsume(QueueName, ((ConsumerParameters)(ChannelParameters)).AutoAckMode == ConsumerParameters.AutoAckModeEnum.Auto, Consumer);
 }
        public async Task <bool> ReplyAsync <T>(T message, IDictionary <string, object> headers = null)
        {
            await Task.Delay(0, LocalCancellationToken);

            if (EndpointType != EndpointTypeEnum.RpcConsumer)
            {
                var e = new InvalidOperationException("Attempt to reply to a message on a non Rpc Consumer prohibited.");
                VerboseLoggingHandler.Log(e);
                throw e;
            }

            var bMessage = EnsureByteArrayFromGeneric(message);

            if (bMessage == null)
            {
                return(false);
            }

            VerboseLoggingHandler.Log($"Replying to message");
            var args = new Dictionary <string, object>();

            if (_rpcResponseChannel == null)
            {
                VerboseLoggingHandler.Log($"Response queue not open yet. Creating one now");
                if (QueueTtlValues.ContainsKey(ReplyToQueueName))
                {
                    args.Add(DictionaryKey_QueueTtl, QueueTtlValues[ReplyToQueueName]);
                }
                VerboseLoggingHandler.Log($"Using requested ttl='{QueueTtlValues[ReplyToQueueName]}'");
                _rpcResponseChannel = _RabbitOut.CreateModel();
                // Use the same TTL value as was used to create the queue on the other side
                _rpcResponseChannel.QueueDeclare(ReplyToQueueName, false, false, true, args);
                VerboseLoggingHandler.Log($"Queue ready");
            }

            var messageProperties = _rpcResponseChannel.CreateBasicProperties();
            var rp = ReplyPriority;

            if (rp > 0)
            {
                rp--;
            }
            messageProperties.Priority   = rp;
            messageProperties.Headers    = headers;
            messageProperties.Type       = MessageTypeFragmentsReply;
            messageProperties.Persistent = false;
            VerboseLoggingHandler.Log($"Publishing reply");
            _rpcResponseChannel.BasicPublish("", ReplyToQueueName, true, messageProperties, bMessage);
            VerboseLoggingHandler.Log($"Sent");
            return(true);
        }
Esempio n. 6
0
        public static RabbitMqEndpoint NewOutboundPublisher(string name, string type, string routingKeyOrTopicName, PublisherParameters p = null, MessageParameters defaultMessageParameters = null, CancellationToken token = default(CancellationToken))
        {
            var exchangeType = GetFullExchangeType(type);

            p ??= new PublisherParameters()
            {
                AcceptReplies = false, AutoDelete = true, Durable = false, EnableConfirmSelect = false, ReplyQueueTtl = 0, Ttl = 6000
            };
            defaultMessageParameters ??= new MessageParameters()
            {
                AutoAck = false, Durable = false, Mandatory = false, Persistent = false, Priority = 3, Resilient = false, TimeOut = 6000
            };

            var ret = new RabbitMqEndpoint
            {
                Channel                  = _RabbitOut.CreateModel(),
                EndpointType             = EndpointTypeEnum.Publisher,
                ExchangeName             = name,
                QueueName                = DefineQueueName(name, exchangeType, "", false),
                RoutingKeyOrTopicName    = routingKeyOrTopicName,
                ExchangeId               = Guid.NewGuid(),
                LocalCancellationToken   = _RabbitOutCts?.Token ?? token,
                ChannelParameters        = p,
                ExchangeType             = GetFullExchangeType(type),
                DefaultMessageParameters = defaultMessageParameters
            };

            VerboseLoggingHandler.Log($"Building a {exchangeType} outbound publisher, name='{name}', routingKeyOrTopicName='{routingKeyOrTopicName}', durable='{p.Durable}', ttl='{p.Ttl}', autoDelete='{p.AutoDelete}', acceptReplies='{p.AcceptReplies}', confirmSelect='{p.EnableConfirmSelect}'");
            ret.ConnectToExchange();

            if (p.EnableConfirmSelect)
            {
                ret.Channel.ConfirmSelect();
            }

            if (p.AcceptReplies)
            {
                VerboseLoggingHandler.Log($"Building a return consumer, ExchangeId='{ret.ExchangeId}', replyQueueTtl='{p.ReplyQueueTtl}'");
                ret.DefineRpcConsumer(ret.ExchangeName, ret.ExchangeId, p.ReplyQueueTtl);
            }

            VerboseLoggingHandler.Log("Exchange ready");
            return(ret);
        }
        private void DefineRpcConsumer(string exchangeName, Guid connectedExchangeId, int ttl = 2000000)
        {
            ttl = 10000000;
            var args = new Dictionary <string, object> {
                { DictionaryKey_QueueTtl, ttl }
            };

            ReturnChannelQueueTtl  = ttl;
            ReturnChannel          = _RabbitIn.CreateModel();
            ReturnChannelQueueName = $"RPC:{exchangeName}:{connectedExchangeId}";
            ReturnChannel.QueueDeclare(ReturnChannelQueueName, false, false, true, args);
            ReturnChannelConsumer           = new AsyncEventingBasicConsumer(_rpcResponseChannel);
            ReturnChannelConsumer.Received += RpcReturnChannelConsumerOnReceivedAsync;
            ReturnChannel.BasicConsume(ReturnChannelQueueName, true, ReturnChannelConsumer);
            ReturnChannelLatch = new SemaphoreSlim(0, 1);


            VerboseLoggingHandler.Log($"Reply queue created, name='{ReturnChannelQueueName}'");
        }
Esempio n. 8
0
        public static RabbitMqEndpoint NewInboundConsumer(string name, string type, string routingKeyOrTopicName = "", ConsumerParameters p = null, CancellationToken token = default(CancellationToken))
        {
            p ??= new ConsumerParameters();
            var exchangeType = GetFullExchangeType(type);
            var ret          = new RabbitMqEndpoint
            {
                Channel                = _RabbitIn.CreateModel(),
                EndpointType           = EndpointTypeEnum.Consumer,
                ExchangeName           = name,
                LocalCancellationToken = _RabbitInCts?.Token ?? token,
                QueueTtlValues         = new Dictionary <string, int>(),
                ChannelParameters      = p,
                ExchangeType           = GetFullExchangeType(type),
                QueueName              = DefineQueueName(name, exchangeType, routingKeyOrTopicName, true),
            };

            VerboseLoggingHandler.Log($"Building a {exchangeType} inbound consumer, name='{name}', routingKeyOrTopicName='{routingKeyOrTopicName}', durable='{p.Durable}', ttl='{p.Ttl}', autoDelete='{p.AutoDelete}', autoAckMode='{p.AutoAckMode}'");
            ret.ConnectToExchange();

            try
            {
                VerboseLoggingHandler.Log($"Binding queue '{ret.QueueName}'");
                ret.Channel.QueueBind(ret.QueueName, name, routingKeyOrTopicName, new Dictionary <string, object>());
            }
            catch (Exception e)
            {
                VerboseLoggingHandler.Log(e);
                throw e;
            }

            VerboseLoggingHandler.Log("Initiating the consumer");
            ret.Consumer = new AsyncEventingBasicConsumer(ret.Channel);

            ret.Consumer.Received += ret.OnIncomingMessageAsync;

            VerboseLoggingHandler.Log("Consumer ready");

            return(ret);
        }
Esempio n. 9
0
        private async Task <byte[]> SendMessageInternal(string routingKeyOrTopicName, byte[] message, IDictionary <string, object> headers, MessageType messageType, MessageParameters p = null)
        {
            if (EndpointType != EndpointTypeEnum.Publisher)
            {
                var e = new InvalidOperationException("Attempt to send a message on a consumer prohibited.");
                VerboseLoggingHandler.Log(e);
                throw e;
            }

            p ??= DefaultMessageParameters;
            if (string.IsNullOrEmpty(routingKeyOrTopicName))
            {
                routingKeyOrTopicName = RoutingKeyOrTopicName;
            }
            VerboseLoggingHandler.Log($"SendMessageInternal sending message, type='{messageType}', routingKeyOrTopicName='{routingKeyOrTopicName}', durable='{p.Durable}', mandatory='{p.Mandatory}', persistent='{p.Persistent}', priority='{p.Priority}', autoAck='{p.AutoAck}', resilient='{p.Resilient}', timeout='{p.TimeOut}' (ms)");
            headers ??= new Dictionary <string, object>();


            byte[] ret = null;

            var messageTypeText = new StringBuilder();

            var messageProperties = Channel.CreateBasicProperties();

            messageProperties.Type       = MessageTypeFragmentsChat;
            messageProperties.Timestamp  = AmqpTimestampNow;
            messageProperties.Priority   = p.Priority;
            messageProperties.Persistent = p.Persistent;
            messageProperties.Expiration = p.TimeOut.ToString();
            if (p.Durable)
            {
                messageProperties.DeliveryMode = 2;
            }

            messageProperties.CorrelationId = ConversationId.ToString();

            if (!p.AutoAck)
            {
                messageTypeText.Append((MessageTypeFragmentsRequestAmqAck));
            }

            if ((messageType & MessageType.RequireAck) == MessageType.RequireAck)
            {
                messageTypeText.Append(MessageTypeFragmentsRequestAck);
            }
            if ((messageType & MessageType.RequireResponse) == MessageType.RequireResponse)
            {
                messageTypeText.Append(MessageTypeFragmentsRequestReply);
            }
            headers.Add(DictionaryKey_PassedQueueTtl, ReturnChannelQueueTtl);

            messageProperties.Type    = messageTypeText.ToString();
            messageProperties.Headers = headers;

            try
            {
                ReturnData = null;
                messageProperties.ReplyTo = ReturnChannelQueueName;
                VerboseLoggingHandler.Log($"Publishing now");
                Channel.BasicPublish(ExchangeName, routingKeyOrTopicName, p.Mandatory, messageProperties, message);
                //_channel.WaitForConfirmsOrDie(new TimeSpan(0, 0, 0, 0, timeout.Value));
                if (((PublisherParameters)(ChannelParameters)).EnableConfirmSelect)
                {
                    try
                    {
                        Channel.WaitForConfirms();
                    }
                    catch (InvalidOperationException e1)
                    {
                        if (e1.Message == "Confirms not selected")
                        {
                            var e = new InvalidOperationException("Invalid configuration. WaitForConfirms behavior requested, but Exchange not configured for them.", e1);
                            VerboseLoggingHandler.Log(e);
                            throw e;
                        }
                        else
                        {
                            VerboseLoggingHandler.Log(e1);
                            throw e1;
                        }
                    }
                }

                if (messageType == MessageType.Normal)
                {
                    return(null);
                }

                VerboseLoggingHandler.Log($"Published. LatchCount='{ReturnChannelLatch.CurrentCount}', timeout='{p.TimeOut}' (ms)");
                await ReturnChannelLatch.WaitAsync(p.TimeOut, LocalCancellationToken);

                VerboseLoggingHandler.Log($"Released. LatchCount='{ReturnChannelLatch.CurrentCount}'");
            }
            finally
            {
                if (messageType != MessageType.Normal)
                {
                    VerboseLoggingHandler.Log($"Completed. LatchCount='{ReturnChannelLatch.CurrentCount}'");
                    ret = ReturnData;
                }
            }

            return(ret);
        }
Esempio n. 10
0
        protected virtual async Task OnIncomingMessageAsync(object sender, BasicDeliverEventArgs ea)
        {
            await Task.Delay(0, LocalCancellationToken);

            var ackMode     = ((ConsumerParameters)ChannelParameters).AutoAckMode;
            var isRpc       = false;
            var requiresAck = false;

            VerboseLoggingHandler.Log($"Event OnIncomingMessageAsync triggered For tag='{ea.DeliveryTag}', exchange='{ea.Exchange}', routingKeyOrTopicName='{ea.RoutingKey}', consumerTag='{ea.ConsumerTag}', deliveryTag='{ea.DeliveryTag}', redelivered='{ea.Redelivered}'");

            var messageType = ea.BasicProperties.Type;

            if (!ea.BasicProperties.IsCorrelationIdPresent())
            {
                var e = new InvalidOperationException($"Missing correlationId in message from exchange={ea.Exchange} deliveryTag=${ea.DeliveryTag}");
                VerboseLoggingHandler.Log(e);
                throw e;
            }

            VerboseLoggingHandler.Log($"MessageType='{messageType}'");

            if (messageType.Contains(MessageTypeFragmentsRequestAmqAck))
            {
                if (ackMode == ConsumerParameters.AutoAckModeEnum.OnReceipt)
                {
                    Channel.BasicAck(ea.DeliveryTag, false);
                }
                if (ackMode == ConsumerParameters.AutoAckModeEnum.Manual)
                {
                    requiresAck = true;
                }
            }

            if ((messageType.Contains(MessageTypeFragmentsRequestAck) || messageType.Contains(MessageTypeFragmentsRequestReply) && ea.BasicProperties.IsReplyToPresent()))
            {
                isRpc            = true;
                EndpointType     = EndpointTypeEnum.RpcConsumer;
                ReplyToQueueName = ea.BasicProperties.ReplyTo;
                VerboseLoggingHandler.Log($"Reply requested to '{ReplyToQueueName}'");

                if (ea.BasicProperties.IsHeadersPresent())
                {
                    VerboseLoggingHandler.Log($"Headers found");

                    var headers = ea.BasicProperties.Headers;
                    if (headers.ContainsKey(DictionaryKey_PassedQueueTtl))
                    {
                        var ttl = Convert.ToInt32(headers[DictionaryKey_PassedQueueTtl]);
                        VerboseLoggingHandler.Log($"ttl='{ttl}'");

                        if (QueueTtlValues.ContainsKey(ReplyToQueueName))
                        {
                            QueueTtlValues[ReplyToQueueName] = ttl;
                        }
                        else
                        {
                            QueueTtlValues.Add(ReplyToQueueName, ttl);
                        }

                        ea.BasicProperties.Headers.Remove(DictionaryKey_PassedQueueTtl);
                    }
                }

                // Handle basic message acknowledgement here.
                if (messageType.Contains(MessageTypeFragmentsRequestAck) && ConvertMessageToString(ea.Body) == MessageContent_Ping)
                {
                    VerboseLoggingHandler.Log($"Ack'ing the Ping");
                    await ReplyAsync(MessageContent_PingResponse, null);
                }
            }

            VerboseLoggingHandler.Log($"Delegate check - does messageType have '{MessageTypeFragmentsRequestReply}'?");
            if (messageType.Contains(MessageTypeFragmentsRequestReply))
            {
                VerboseLoggingHandler.Log($"Confirmed. Fire delegate");
                var args = new IncomingRabbitMqMessageEventArgs(isRpc, requiresAck, ea);
                await Task.Run(() => IncomingMessage?.Invoke(this, args), LocalCancellationToken);
            }
        }
Esempio n. 11
0
        public static bool ConnectToRabbit(List <string> hosts, string virtualHost, string userName, string password, int port, string applicationName, int connectionRetryWait = 6000, int retries = 60, CancellationTokenSource inOrInAndOutCts = null, CancellationTokenSource outCts = null)
        {
            if (Initialized)
            {
                return(true);
            }

            var factory = new ConnectionFactory
            {
                UserName                 = userName,
                Password                 = password,
                VirtualHost              = virtualHost,
                DispatchConsumersAsync   = true,
                RequestedHeartbeat       = new TimeSpan(0, 0, 10),
                AutomaticRecoveryEnabled = true,
                NetworkRecoveryInterval  = TimeSpan.FromSeconds(10),
                Port = port switch
                {
                    0 => AmqpTcpEndpoint.UseDefaultPort,
                    -1 => AmqpTcpEndpoint.DefaultAmqpSslPort,
                    _ => port
                }
            };

            _RabbitIn     = Connect(_RabbitIn, "Consumer", retries, connectionRetryWait);
            _RabbitOut    = Connect(_RabbitOut, "Exchange", retries, connectionRetryWait);
            _RabbitInCts  = inOrInAndOutCts ?? new CancellationTokenSource();
            _RabbitOutCts = outCts ?? inOrInAndOutCts;

            return(Initialized);

            IConnection Connect(IConnection c, string type, int r, int t)
            {
                Exception le = null;

                if (c != null && c.IsOpen)
                {
                    return(c);
                }
                while (c == null || (!c.IsOpen && --r != 0))
                {
                    try
                    {
                        c = factory.CreateConnection(hosts, applicationName);
                        if (c.IsOpen)
                        {
                            return(c);
                        }
                    }
                    catch (BrokerUnreachableException e)
                    {
                        Task.Delay(t);
                        le = e;
                    }
                    catch (Exception e)
                    {
                        le = e;
                        break;
                    }
                }

                var ex = new CannotConnectToRabbitException($"Unable to make {type} connections to rabbit", le);

                VerboseLoggingHandler.Log(ex);
                throw ex;
            }
        }
Esempio n. 12
0
 private static void ChannelOnBasicAcks(object sender, BasicAckEventArgs e)
 {
     VerboseLoggingHandler.Log($"Event ChannelOnBasicAcks triggered For tag='{e.DeliveryTag}', multiple='{e.Multiple}'");
 }
Esempio n. 13
0
 private static void ChannelOnModelShutdown(object sender, ShutdownEventArgs e)
 {
     VerboseLoggingHandler.Log($"Event ChannelOnModelShutdown triggered - Initiator {e.Initiator.ToString()}, classId={e.ClassId} methodId={e.MethodId}, replyCode={e.ReplyCode}. ReplyText '{e.ReplyText}'");
 }
Esempio n. 14
0
 private static void ChannelOnCallbackException(object sender, CallbackExceptionEventArgs e)
 {
     VerboseLoggingHandler.Log($"Event ChannelOnCallbackException triggered: {e.Detail}");
     VerboseLoggingHandler.Log(e.Exception);
 }
Esempio n. 15
0
 private static void ChannelOnBasicReturn(object sender, BasicReturnEventArgs e)
 {
     VerboseLoggingHandler.Log($"Event ChannelOnBasicReturn triggered Exchange='{e.Exchange}', routingKeyOrTopicName='{e.RoutingKey}', replyText='{e.ReplyText}'");
 }