/// <summary> /// 订阅消息 /// </summary> /// <param name="receiveMessageFun">接收消息回调</param> /// <param name="isAutoAck">是否自动应答,如果为否,则需要在回调里返回true</param> public void Subscribe(Func <byte[], bool> receiveMessageFun, bool isAutoAck = false) { if (receiveMessageFun == null) { return; } var consumer = new EventingBasicConsumer(channel); consumer.Received += (o, e) => { if (e.Body.IsEmpty) { // 如果自动回答,则什么都不用干 if (isAutoAck) { return; } channel.BasicAck(e.DeliveryTag, false); return; } bool isAck = true; string logMsg = $"{GetLogTitleMsg()}.接收到消息"; log.DebugAsync(logMsg, null, tags: GetLogTags()); var data = e.Body.ToArray(); try { isAck = receiveMessageFun(data); } catch (Exception ex) { var busEx = AmqpUtil.BuilderBusinessException(ex, $"字节数组数据转换为Base64:{Convert.ToBase64String(data)}", amqpQueue, log, ex.Message); isAck = ExceptionHandle.Handle(busEx); logMsg = $"{GetLogTitleMsg()}.输入参数isAutoAck:{isAutoAck},业务处理发生异常(返回应答为{isAck})"; log.ErrorAsync(logMsg, ex, tags: GetLogTags()); } // 如果自动回答,则什么都不用干 if (isAutoAck) { return; } // 如果业务端返回应答,则返回MQ已成功处理,否则返回未处理成功,需要将该消息放回队列进行重试 if (isAck) { channel.BasicAck(e.DeliveryTag, false); } else { channel.BasicNack(e.DeliveryTag, false, true); } }; channel.BasicConsume(amqpQueue.Queue.Name, isAutoAck, consumer); }
/// <summary> /// 订阅消息 /// </summary> /// <param name="receiveMessageFun">接收消息回调</param> /// <param name="receiveMessageType">接收消息类型</param> /// <param name="isAutoAck">是否自动应答,如果为否,则需要在回调里返回true</param> public void Subscribe(Func <object, bool> receiveMessageFun, Type receiveMessageType, bool isAutoAck = false) { if (receiveMessageFun == null) { return; } Subscribe((byte[] x) => { object data = null; try { data = BytesSerialization.Deserialize(x, receiveMessageType); } catch (MessagePackSerializationException) { // 如果messagepack反序列失败,则使用json反列化 try { data = jsonSerialization.Deserialize(x, receiveMessageType); } catch (Exception ex) { string logMsg = $"{GetLogTitleMsg()}.输入参数isAutoAck:{isAutoAck},jsonSerialization.Deserialize发生异常(返回应答为true),认为是不符合业务规范的数据,应删除消息"; log.ErrorAsync(logMsg, ex, tags: GetLogTags()); // 反序列异常则返回true return(true); } } catch (Exception ex) { string logMsg = $"{GetLogTitleMsg()}.输入参数isAutoAck:{isAutoAck},BytesSerialization.Deserialize发生异常(返回应答为true),认为是不符合业务规范的数据,应删除消息"; log.ErrorAsync(logMsg, ex, tags: GetLogTags()); // 反序列异常则返回true return(true); } try { return(receiveMessageFun(data)); } catch (Exception ex) { var busEx = AmqpUtil.BuilderBusinessException(ex, data, amqpQueue, log, ex.Message); var isAck = ExceptionHandle.Handle(busEx); string logMsg = $"{GetLogTitleMsg()}.输入参数isAutoAck:{isAutoAck},业务处理发生异常(返回应答为{isAck})"; log.ErrorAsync(logMsg, ex, tags: GetLogTags()); return(isAck); } }, isAutoAck); }
/// <summary> /// 构造方法 /// </summary> /// <param name="amqpConfigReader">AMQP配置读取</param> /// <param name="connectionFactory">连接工厂</param> public AmqpRpcClientMethodBase(IAmqpConfigReader amqpConfigReader, IAmqpConnectionFactory connectionFactory) { if (amqpConfigReader == null) { this.amqpConfigReader = AmqpUtil.GetConfigReader(amqpConfigReader); } else { this.amqpConfigReader = amqpConfigReader; } this.connectionFactory = connectionFactory; }
/// <summary> /// 订阅消息 /// </summary> /// <typeparam name="T">接收类型</typeparam> /// <param name="receiveMessageFun">接收消息回调</param> /// <param name="isAutoAck">是否自动应答,如果为否,则需要在回调里返回true</param> public void Subscribe <T>(Func <T, bool> receiveMessageFun, bool isAutoAck = false) { Subscribe((byte[] x) => { if (receiveMessageFun != null) { T data = default(T); try { data = BytesSerialization.Deserialize <T>(x); } catch (Exception ex) { string logMsg = $"{GetLogTitleMsg()}.输入参数isAutoAck:{isAutoAck},BytesSerialization.Deserialize发生异常(返回应答为true),认为是不符合业务规范的数据,应删除消息"; log.ErrorAsync(logMsg, ex, tags: GetLogTags()); // 反序列异常则返回true return(true); } try { return(receiveMessageFun(data)); } catch (Exception ex) { var busEx = AmqpUtil.BuilderBusinessException(ex, data, amqpQueue, log, ex.Message); var isAck = ExceptionHandle.Handle(busEx); string logMsg = $"{GetLogTitleMsg()}.输入参数isAutoAck:{isAutoAck},业务处理发生异常(返回应答为{isAck})"; log.ErrorAsync(logMsg, ex, tags: GetLogTags()); return(isAck); } } return(true); }, isAutoAck); }
/// <summary> /// 订阅消息 /// </summary> /// <param name="receiveMessageFun">接收消息回调</param> /// <param name="isAutoAck">是否自动应答,如果为否,则需要在回调里返回true</param> public void Subscribe(Func <string, bool> receiveMessageFun, bool isAutoAck = false) { Subscribe((byte[] x) => { if (receiveMessageFun != null) { string msg = null; try { msg = Encoding.UTF8.GetString(x); } catch (Exception ex) { string logMsg = $"{GetLogTitleMsg()}.输入参数isAutoAck:{isAutoAck},Encoding.UTF8.GetString发生异常,返回应答:true"; log.ErrorAsync(logMsg, ex, tags: GetLogTags()); return(true); } try { return(receiveMessageFun(msg)); } catch (Exception ex) { var busEx = AmqpUtil.BuilderBusinessException(ex, msg, amqpQueue, log, ex.Message); var isAck = ExceptionHandle.Handle(busEx); string logMsg = $"{GetLogTitleMsg()}.输入参数isAutoAck:{isAutoAck},业务处理发生异常(返回应答为{isAck})"; log.ErrorAsync(logMsg, ex, tags: GetLogTags()); return(isAck); } } return(true); }, isAutoAck); }
/// <summary> /// 接收消息 /// </summary> /// <param name="receiveMessageFun">接收消息回调</param> public void Receive(Func <byte[], byte[]> receiveMessageFun) { channel.QueueDeclare(queue: amqpQueue.Queue.Name, durable: amqpQueue.Persistent, exclusive: false, autoDelete: amqpQueue.Queue.AutoDelQueue, arguments: null); if (amqpQueue.Queue.Qos != null) { channel.BasicQos(0, amqpQueue.Queue.Qos.GetValueOrDefault(), false); } channel.QueueBind(amqpQueue.Queue.Name, amqpQueue.ExchangeName, amqpQueue.Queue.Name); var consumer = new EventingBasicConsumer(channel); channel.BasicConsume(queue: amqpQueue.Queue.Name, autoAck: false, consumer: consumer); consumer.Received += (model, ea) => { // 错误返回信息 BasicReturnInfo errorReturn = null; // 返回给客户端的数据 byte[] outData = null; // 关联ID string correlationId = null; IBasicProperties props = null; IBasicProperties replyProps = null; try { props = ea.BasicProperties; replyProps = channel.CreateBasicProperties(); replyProps.CorrelationId = props.CorrelationId; correlationId = props.CorrelationId; byte[] inData = ea.Body.IsEmpty ? null : ea.Body.ToArray(); try { outData = receiveMessageFun(inData); } catch (Exception ex) { var busEx = AmqpUtil.BuilderBusinessException(ex, null, amqpQueue, log, ex.Message); ExceptionHandle.Handle(busEx); log.ErrorAsync("RpcServer回调业务处理出现异常", ex, typeof(RabbitRpcServer).Name, correlationId); errorReturn = new BasicReturnInfo(); errorReturn.SetFailureMsg("业务处理出现异常", ex.Message); outData = Encoding.UTF8.GetBytes(JsonUtil.SerializeIgnoreNull(errorReturn)); } } catch (Exception ex) { log.ErrorAsync("RpcServer接收消息处理出现异常", ex, typeof(RabbitRpcServer).Name, correlationId); errorReturn = new BasicReturnInfo(); errorReturn.SetFailureMsg("RpcServer接收消息处理出现异常", ex.Message); outData = Encoding.UTF8.GetBytes(JsonUtil.SerializeIgnoreNull(errorReturn)); } finally { if (props != null && replyProps != null) { channel.BasicPublish(exchange: amqpQueue.ExchangeName, routingKey: props.ReplyTo, basicProperties: replyProps, body: outData); channel.BasicAck(deliveryTag: ea.DeliveryTag, multiple: false); } } }; }
/// <summary> /// 构造方法 /// </summary> /// <param name="symmetricalEncryption">加密</param> /// <param name="appConfig">应用配置</param> /// <param name="amqpConfigReader">配置读取</param> public RabbitConnectionFactory(ISymmetricalEncryption symmetricalEncryption = null, IAppConfiguration appConfig = null, IAmqpConfigReader amqpConfigReader = null) : base(symmetricalEncryption, appConfig) { this.amqpConfigReader = AmqpUtil.GetConfigReader(amqpConfigReader); }