/// <summary> /// Отписать потребителя от очереди. /// </summary> /// <param name="tag">Тег потребителя сообщений.</param> public void BeginCancel(string tag) { if (!RegistratedConsumers.TryGetValue(tag, out var consumer)) { return; } consumer.Consumer.Received -= consumer.Handler; RegistratedConsumers.Remove(tag); Model.BasicCancelNoWait(tag); }
/// <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); }