/// <summary> /// The Publish. /// </summary> /// <typeparam name="TObject">.</typeparam> /// <param name="produceConfig">The produceConfig<see cref="Func{MqSettings}"/>.</param> /// <param name="jsonBody">The jsonBody<see cref="Func{string}"/>.</param> /// <returns>The <see cref="bool"/>.</returns> public bool Publish <TObject>(Func <MqSettings> produceConfig, Func <string> jsonBody) { MqSettings config = produceConfig(); if (string.IsNullOrWhiteSpace(config.QueueName)) { throw new Exception($"{nameof(config.QueueName)}不可为空"); } try { if (_channel == null || _channel.IsClosed) { _channel = _connection.CreateModel(); //设置交换器及类型 _channel.ExchangeDeclare( config.ExChangeName, config.ExChangeType, config.Durable, config.AutoDelete, config.Arguments); //声明队列 _channel.QueueDeclare( queue: config.QueueName, //队列名称 durable: config.Durable, //是否持久化 true exclusive: config.Exclusive, //是否排它性 false autoDelete: config.AutoDelete, //是否自动删除 false arguments: config.Arguments); //绑定消息队列 _channel.QueueBind( queue: config.QueueName, //队列 exchange: config.ExChangeName, //交换器 routingKey: config.RoutingKey, //routingkey arguments: config.Arguments); } //持久化队列 var properties = _channel.CreateBasicProperties(); properties.Persistent = true; //转换消息数据 if (string.IsNullOrWhiteSpace(jsonBody())) { throw new Exception($"委托参数{nameof(jsonBody)}不可为空。"); } var body = Encoding.UTF8.GetBytes(jsonBody()); //发送消息 _channel.BasicPublish( exchange: config.ExChangeName, routingKey: config.RoutingKey, mandatory: true,//如果exchange根据自身类型和消息routingKey无法找到一个合适的queue存储消息,那么broker会调用basic.return方法将消息返还给生产者;false:将直接丢弃 basicProperties: properties, body: body); return(true); } catch (Exception ex) { _logger.LogError(exception: ex, $"{nameof(MqService)}.Publish 出现异常"); return(false); } }
/// <summary> /// The Subscribe. /// </summary> /// <param name="settings">The settings<see cref="Func{MqSettings}"/>.</param> /// <param name="func">The func<see cref="Func{string, bool}"/>.</param> public void Subscribe(Func <MqSettings> settings, Func <string, bool> func) { MqSettings config = settings(); if (string.IsNullOrWhiteSpace(config.QueueName)) { throw new Exception($"{nameof(config.QueueName)}不可为空"); } try { Task.Run(() => { if (_channel == null || _channel.IsClosed) { _channel = _connection.CreateModel(); //设置交换器及类型 _channel.ExchangeDeclare( config.ExChangeName, config.ExChangeType, config.Durable, config.AutoDelete, config.Arguments); //声明队列 _channel.QueueDeclare( queue: config.QueueName, //队列名称 durable: config.Durable, //是否持久化 true exclusive: config.Exclusive, //是否排它性 false autoDelete: config.AutoDelete, //是否自动删除 false arguments: config.Arguments); } //此处临时如此处理,后面有特殊需求在做扩展,这里是一次从队列拿一条 _channel.BasicQos(prefetchSize: 0, prefetchCount: 1, global: false);//告诉broker同一时间只处理一个消息 var consumer = new EventingBasicConsumer(_channel); consumer.Received += (currentConsumer, ea) => { try { lock (_object) { var body = ea.Body; var message = Encoding.UTF8.GetString(body); _logger.LogInformation($"接收到{config.QueueName}消息: {message} )"); bool blnResult = func(message); if (blnResult) { _logger.LogInformation($"MQConsumerService.Subscribor 调用委托执行完成"); if (!config.AutoAck) { _channel.BasicAck(ea.DeliveryTag, false); //手动应答 IBasicProperties props = ea.BasicProperties; //传来的属性 _channel.BasicPublish(ea.Exchange, ea.RoutingKey, props, ea.Body); } else { _channel.BasicAck(ea.DeliveryTag, true); } } else { _logger.LogWarning($"消费端回调函执行结果为:{blnResult}"); } } } catch (Exception ex) { _logger.LogError(ex, "MQConsumerService.Subscribor 执行失败"); if (!config.AutoAck) { /* * 此种方式存在缺陷,方便其他人学习,所以我写在这,会导致一个很严重的结果就是消息在消费失败之后回退队列时,会一直处于队列末尾, * 这样会循环往复的被处理,如果一直失败,其他消息也失败,长期会导致消息堆积,大量堆积。 */ //channel.BasicReject(ea.DeliveryTag, command.Requeue); //换成以下方式(将错误或消费失败消息推送到队列尾部) _channel.BasicAck(ea.DeliveryTag, false); //手动应答 IBasicProperties props = ea.BasicProperties; //传来的属性 _channel.BasicPublish(ea.Exchange, ea.RoutingKey, props, ea.Body); _logger.LogError(ex, "MQConsumerService.Subscribor.catch 已将消息重新推到队列(头部) "); } } }; _channel.BasicConsume(queue: config.QueueName, autoAck: config.AutoAck, consumer: consumer); _logger.LogInformation($"StartConsumer Successed"); Thread.Sleep(Timeout.Infinite); }); } catch (Exception ex) { _logger.LogError(exception: ex, $"{nameof(MqService)}.Consumer 出现异常"); } }