/// <summary> /// 注册消息处理器,根据模式匹配接收消息 /// </summary> /// <typeparam name="TMessage">消息类型</typeparam> /// <typeparam name="THandler">消息处理器类型</typeparam> /// <param name="subscriberName">订阅器的名称</param> /// <param name="redeliveryCheck">是否开启重发确认;如果消息处理器逻辑已经实现为幂等则不需要开启以便节省计算资源,否则请打开该选项</param> /// <param name="subscribePatterns">订阅器支持的消息模式</param> public void RegisterTopicHandler <TMessage, THandler>(string routeKey, string exchangeName = "", string queueName = "") where THandler : BaseHandleMessages <TMessage> where TMessage : BaseMessage { if (string.IsNullOrWhiteSpace(routeKey)) { throw new ArgumentNullException("routeKey"); } try { var type = typeof(TMessage); var handler = Activator.CreateInstance <THandler>(); var channel = connection.CreateModel(); var consumer = new EventingBasicConsumer(channel); /* * @param prefetchSize maximum amount of content (measured in octets) that the server will deliver, 0 if unlimited * @param prefetchCount maximum number of messages that the server will deliver, 0 if unlimited * @param global true if the settings should be applied to the entire channel rather than each consumer */ channel.BasicQos(0, prefetch_count, false); consumer.Received += async(model, ea) => { var json = Encoding.UTF8.GetString(ea.Body); var msg = JsonConvert.DeserializeObject <TMessage>(json); await handler.Handle(msg); if (msg.NeedNAck) { channel.BasicNack(ea.DeliveryTag, false, true); } else { channel.BasicAck(ea.DeliveryTag, false); } }; var exchange = string.Empty; var queue = string.Empty; if (!string.IsNullOrEmpty(exchangeName) && !string.IsNullOrEmpty(queueName)) { exchange = exchangeName; queue = queueName; EnsureQueue.TopicEnsureQueue(channel, routeKey, ref exchange, ref queue); } else { EnsureQueue.TopicEnsureQueue(channel, type, routeKey, out exchange, out queue); } channel.BasicConsume(queue, false, consumer); } catch (Exception ex) { _logger.Debug("RegisterTopicHandler出错,异常:" + ex.Message + ";堆栈:" + ex.StackTrace); } }
/// <summary> /// 注册消息处理器,fanout模式 /// </summary> /// <typeparam name="TMessage">消息类型</typeparam> /// <typeparam name="THandler">消息处理器类型</typeparam> public void RegisterFanoutHandler <TMessage, THandler>(string exchangeName = "") where THandler : BaseHandleMessages <TMessage> where TMessage : BaseMessage { try { var type = typeof(TMessage); var handler = Activator.CreateInstance <THandler>(); var channel = connection.CreateModel(); var consumer = new EventingBasicConsumer(channel); var exchange = string.Empty; if (!string.IsNullOrEmpty(exchangeName)) { exchange = exchangeName; EnsureQueue.FanoutEnsureQueue(channel, ref exchange); } else { EnsureQueue.FanoutEnsureQueue(channel, type, out exchange); } TMessage msg = null;//闭包获取数据 try { consumer.Received += async(model, ea) => { var json = Encoding.UTF8.GetString(ea.Body); msg = JsonConvert.DeserializeObject <TMessage>(json); await handler.Handle(msg); }; } catch (Exception ex) { _message_queue_helper.UpdateCanbeRemoveIsFalse(msg.MsgHash); _logger.Error("RegisterFanoutHandler()出错,异常:" + ex.Message + ";堆栈:" + ex.StackTrace); } //将一个随机队列绑定(bind)到交换机上面 var queueName = channel.QueueDeclare().QueueName; channel.QueueBind(queue: queueName, exchange: exchange, routingKey: ""); channel.BasicConsume(queueName, true, consumer); } catch (Exception ex) { _logger.Debug("RegisterFanoutHandler()出错,异常:" + ex.Message + ";堆栈:" + ex.StackTrace); } }
private static bool SendFanout(BaseMessage message, int delaySend = 0) { if (string.IsNullOrWhiteSpace(message.Source)) { throw new ArgumentNullException("message.Source"); } ///fanout模式不同其他模式,又无法获取到订阅者数量,于是直接默认CanbeRemove为true ///如果出现异常在设为false,具体在哪儿失败了,怎么恢复就需要调用者自己去查了 ///数据库消息只提供一个记录,供查证用 if (!PrePersistMessage(message, true)) { return(false); } var messageType = message.GetType(); using (var pooled = InnerCreateChannel(messageType)) { IModel channel = pooled.Channel; // pooled.PreRecord(message.MsgHash);无需修改状态了 var exchange = string.Empty; if (!string.IsNullOrEmpty(message.exchangeName)) { exchange = message.exchangeName; EnsureQueue.FanoutEnsureQueue(channel, ref exchange, delaySend); } else { EnsureQueue.FanoutEnsureQueue(channel, messageType, out exchange, delaySend); } var json = JsonConvert.SerializeObject(message); var bytes = Encoding.UTF8.GetBytes(json); var props = channel.CreateBasicProperties(); props.Persistent = true; channel.BasicPublish(exchange, "", props, bytes); var time_out = Math.Max(default_retry_wait, message.RetryCount_Publish * 2 /*2倍往上扩大,防止出现均等*/ * 1000); var ret = channel.WaitForConfirms(TimeSpan.FromMilliseconds(time_out)); if (!ret) { if (message.RetryCount_Publish < default_retry_count) { var ok = _message_queue_helper.Update( message.MsgHash, fromStatus1: MsgStatus.Created, // 之前的状态只能是1 Created 或者2 Retry fromStatus2: MsgStatus.Retrying, toStatus: MsgStatus.Retrying); if (ok) { message.RetryCount_Publish += 1; message.LastRetryTime = DateTime.Now; fanout_queue.Enqueue(message); return(true); } throw new Exception("数据库update出现异常"); } throw new Exception($"消息发送超过最大重试次数({default_retry_count}次)"); } } return(true); }
private static bool SendTopic(BaseMessage message, int delaySend = 0) { if (string.IsNullOrWhiteSpace(message.Source)) { throw new ArgumentNullException("message.Source"); } if (string.IsNullOrWhiteSpace(message.routeKey)) { throw new ArgumentNullException("routeKey"); } if (!PrePersistMessage(message)) { return(false); } var messageType = message.GetType(); delaySend = delaySend == 0 ? delaySend : Math.Max(delaySend, 1000); // 至少保证1秒的延迟,否则意义不大 using (var pooled = InnerCreateChannel(messageType)) { IModel channel = pooled.Channel; pooled.PreRecord(message.MsgHash); var exchange = string.Empty; var queue = string.Empty; if (!string.IsNullOrEmpty(message.exchangeName) && !string.IsNullOrEmpty(message.queueName)) { exchange = message.exchangeName; queue = message.queueName; EnsureQueue.TopicEnsureQueue(channel, message.routeKey, ref exchange, ref queue, delaySend); } else { EnsureQueue.TopicEnsureQueue(channel, messageType, message.routeKey, out exchange, out queue, delaySend); } var json = JsonConvert.SerializeObject(message); var bytes = Encoding.UTF8.GetBytes(json); var props = channel.CreateBasicProperties(); props.ContentType = "text/plain"; props.DeliveryMode = 2; channel.BasicPublish(exchange, message.routeKey, props, bytes); var time_out = Math.Max(default_retry_wait, message.RetryCount_Publish * 2 /*2倍往上扩大,防止出现均等*/ * 1000); var ret = channel.WaitForConfirms(TimeSpan.FromMilliseconds(time_out)); if (!ret) { if (message.RetryCount_Publish < default_retry_count) { var ok = _message_queue_helper.Update( message.MsgHash, fromStatus1: MsgStatus.Created, // 之前的状态只能是1 Created 或者2 Retry fromStatus2: MsgStatus.Retrying, toStatus: MsgStatus.Retrying); if (ok) { message.RetryCount_Publish += 1; message.LastRetryTime = DateTime.Now; topic_queue.Enqueue(message); return(true); } throw new Exception("数据库update出现异常"); } throw new Exception($"消息发送超过最大重试次数({default_retry_count}次)"); } } return(true); }