示例#1
0
        /// <summary>
        /// Начать получать сообщения со одной конечной точки.
        /// </summary>
        /// <param name="endpoint">Конечная точка.</param>
        /// <returns>Тег потребителя сообщений.</returns>
        public string BeginConsume(EndpointConfig endpoint)
        {
            var consumer = new EventingBasicConsumer(Model);

            void OnConsumerOnReceived(object sender, BasicDeliverEventArgs e)
            {
                try
                {
                    if (string.IsNullOrEmpty(e.BasicProperties.Type))
                    {
                        var message = Serializer.DeserializeTransferMessage(e.Body, out var type, Dispatcher.TryGetByAlias);

                        // Обработать сообщение, если оно подразумевает только получение
                        Dispatcher.DispatchMessage(this, (ack, requeue, order) => Acknowledgment(endpoint, e, ack, requeue, order), message, type);
                    }
                    else if (e.BasicProperties.Type == RpcRequestHeaderName)
                    {
                        try
                        {
                            // Найти соответствующий делегат в списке ожидающих
                            try
                            {
                                ValidateRpcMessageArgs(e);
                            }
                            catch (Exception ex)
                            {
                                Logger.LogError(ex, $"Ошибка обработки сообщения DeliveryTag: {e.DeliveryTag}");
                            }

                            var props = Model.CreateBasicProperties();
                            props.CorrelationId = e.BasicProperties.CorrelationId;
                            props.Type          = RpcResponseHeaderName;
                            try
                            {
                                var argTypeName  = Encoding.UTF8.GetString((byte[])e.BasicProperties.Headers[RpcArgType]);
                                var respTypeName = Encoding.UTF8.GetString((byte[])e.BasicProperties.Headers[RpcRespType]);

                                Logger.LogTrace($"Reviced msg argType: {argTypeName} respType: {respTypeName}");

                                // Обработать сообщение
                                var argType  = Type.GetType(argTypeName);
                                var respType = Type.GetType(respTypeName);
                                if (argType == null)
                                {
                                    throw new ArgumentException($"Не удалось найти тип аргумента запроса: {argTypeName}");
                                }

                                if (respType == null)
                                {
                                    throw new ArgumentException($"Не удалось найти тип аргумента ответа: {respTypeName}");
                                }

                                var message        = Serializer.DeserializeRpcMessage(e.Body, argType);
                                var response       = Dispatcher.HandleRpcMessage(this, message, (ack, requeue, order) => Acknowledgment(endpoint, e, ack, requeue, order), argType, respType);
                                var responseObject = new RpcResponse(ResponseType.Ok, response, string.Empty);
                                props.Headers = new Dictionary <string, object> {
                                    { RpcRespType, e.BasicProperties.Headers[RpcRespType] },
                                };

                                // Отправить сообщение в очередь ответа
                                PublishRpc(e.BasicProperties.ReplyTo, responseObject, props, responseObject.GetType());
                                Model.BasicAck(e.DeliveryTag, true);
                            }
                            catch (Exception ex)
                            {
                                // Отправить сообщение об ошибке
                                var responseObject = new RpcResponse(ResponseType.Error, new object(), ex.ToString());
                                Logger.Log(LogLevel.Error, ex, "Ошибка во время обработки RPC сообщения");
                                PublishRpc(e.BasicProperties.ReplyTo, responseObject, props, responseObject.GetType());
                                Model.BasicNack(e.DeliveryTag, false, false);
                            }
                        }
                        catch (Exception ex)
                        {
                            throw new InvalidDataContractException($"Невозможно ответить на RPC сообщение TAG: [{e.DeliveryTag}] CT: [{e.ConsumerTag}] т.к. заголовки сформированы с ошибкой", ex);
                        }
                    }
                    else
                    {
                        throw new NotSupportedException($"Неподдерживаемый тип сообщения: [{e.BasicProperties.Type}]");
                    }
                }
                catch (Exception ex)
                {
                    if (!endpoint.AutoAck)
                    {
                        Acknowledgment(endpoint, e, false, false, true);
                    }

                    Logger.LogError(ex, $"Клиенту не удалось обработать сообщение DeliveryTag {e.DeliveryTag} из-за ошибки");
                    if (BehavioursDict.TryGetValue(MessageProcessPhase.OnError, out var behaviours))
                    {
                        foreach (var messageProcessBehaviuor in behaviours)
                        {
                            Logger.Log(LogLevel.Debug, $"Отработка вызова поведения фаза [{MessageProcessPhase.OnError}]: {messageProcessBehaviuor}");
                            try
                            {
                                messageProcessBehaviuor.InvokeBehaviour(e.Body);
                            }
                            catch (Exception bex)
                            {
                                Logger.Log(LogLevel.Error, bex, $"Ошибка во время отработки поведения: [{messageProcessBehaviuor}]");
                            }
                        }
                    }
                }
            }

            consumer.Received += OnConsumerOnReceived;

            var tag = Model.BasicConsume(endpoint.EndpointName, endpoint.AutoAck, consumer);

            if (!RegistratedConsumers.ContainsKey(tag))
            {
                RegistratedConsumers.Add(tag, (consumer, OnConsumerOnReceived));
            }
            else
            {
                throw new Exception($"Получатель сообщений уже зарегистрирован: {tag} - {endpoint.EndpointName}");
            }

            return(tag);
        }