RabbitMQ 封装,基于原生 RabbitMQ.Client 实现

基于原生 RabbitMQ.Client 实现,包含高可用、高可靠、可监控、可扩展四大核心特性,适配分布式系统生产部署要求;

一、核心依赖

bash 复制代码
# 必须依赖
Install-Package RabbitMQ.Client -Version 6.8.1
Install-Package Newtonsoft.Json -Version 13.0.3
# 可选:日志框架(生产环境建议使用)
Install-Package Serilog -Version 3.1.1
Install-Package Serilog.Sinks.Console -Version 4.1.0
Install-Package Serilog.Sinks.File -Version 5.0.0

二、生产级封装代码

1. 配置类(支持多环境配置)
cs 复制代码
using System;
using System.Collections.Generic;
using RabbitMQ.Client;

/// <summary>
/// RabbitMQ生产环境配置
/// 建议从配置文件读取(如appsettings.json)
/// </summary>
public class RabbitMqProductionConfig
{
    /// <summary>
    /// 集群节点(支持多个,逗号分隔:host1:port1,host2:port2)
    /// </summary>
    public string Nodes { get; set; } = "localhost:5672";

    /// <summary>
    /// 用户名
    /// </summary>
    public string UserName { get; set; } = "guest";

    /// <summary>
    /// 密码
    /// </summary>
    public string Password { get; set; } = "guest";

    /// <summary>
    /// 虚拟主机
    /// </summary>
    public string VirtualHost { get; set; } = "/";

    /// <summary>
    /// 交换机名称
    /// </summary>
    public string ExchangeName { get; set; } = "prod.exchange";

    /// <summary>
    /// 交换机类型(direct/fanout/topic)
    /// </summary>
    public string ExchangeType { get; set; } = ExchangeType.Direct;

    /// <summary>
    /// 队列名称
    /// </summary>
    public string QueueName { get; set; } = "prod.queue";

    /// <summary>
    /// 路由键
    /// </summary>
    public string RoutingKey { get; set; } = "prod.key";

    /// <summary>
    /// 是否持久化(生产环境必须true)
    /// </summary>
    public bool Durable { get; set; } = true;

    /// <summary>
    /// 预取数(控制单消费者并发数,生产环境建议5-20)
    /// </summary>
    public ushort PrefetchCount { get; set; } = 10;

    /// <summary>
    /// 消息过期时间(毫秒)
    /// </summary>
    public int MessageTtl { get; set; } = 300000; // 5分钟

    /// <summary>
    /// 队列最大长度(防止消息堆积撑爆磁盘)
    /// </summary>
    public int QueueMaxLength { get; set; } = 100000;

    /// <summary>
    /// 连接超时时间(毫秒)
    /// </summary>
    public int ConnectionTimeout { get; set; } = 30000;

    /// <summary>
    /// 心跳间隔(秒)
    /// </summary>
    public int HeartbeatSeconds { get; set; } = 60;

    /// <summary>
    /// 最大重试次数(消费失败后)
    /// </summary>
    public int MaxRetryCount { get; set; } = 3;

    /// <summary>
    /// 死信交换机后缀(自动拼接:{ExchangeName}.dlx)
    /// </summary>
    public string DeadLetterExchangeSuffix { get; set; } = ".dlx";

    /// <summary>
    /// 死信路由键后缀(自动拼接:{RoutingKey}.dlk)
    /// </summary>
    public string DeadLetterRoutingKeySuffix { get; set; } = ".dlk";
}

/// <summary>
/// 生产环境消息体(带校验、链路追踪)
/// </summary>
/// <typeparam name="T"></typeparam>
public class RabbitMqProductionMessage<T>
{
    /// <summary>
    /// 消息唯一ID(幂等性校验)
    /// </summary>
    public string MessageId { get; set; } = Guid.NewGuid().ToString("N");

    /// <summary>
    /// 业务数据
    /// </summary>
    public T Data { get; set; } = default!;

    /// <summary>
    /// 链路追踪ID
    /// </summary>
    public string TraceId { get; set; } = Guid.NewGuid().ToString("N");

    /// <summary>
    /// 生产者服务名称
    /// </summary>
    public string ProducerService { get; set; } = string.Empty;

    /// <summary>
    /// 发送时间(UTC)
    /// </summary>
    public DateTime SendTimeUtc { get; set; } = DateTime.UtcNow;

    /// <summary>
    /// 校验消息有效性
    /// </summary>
    /// <returns></returns>
    public bool Validate()
    {
        return !string.IsNullOrEmpty(MessageId) && 
               !string.IsNullOrEmpty(TraceId) && 
               Data != null;
    }
}
2. 核心工具类(生产级)
cs 复制代码
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Newtonsoft.Json;
using RabbitMQ.Client;
using RabbitMQ.Client.Events;
using RabbitMQ.Client.Exceptions;
using Serilog;

/// <summary>
/// RabbitMQ生产级操作类
/// 特性:高可用、自动重连、死信队列、幂等消费、链路追踪
/// </summary>
public class RabbitMqProductionClient : IDisposable
{
    #region 私有字段
    private readonly RabbitMqProductionConfig _config;
    private readonly ILogger _logger;
    private readonly ConcurrentDictionary<string, IConnection> _connectionPool;
    private readonly object _lockObj = new object();
    private readonly JsonSerializerSettings _jsonSettings;

    private IModel? _publishChannel;
    private IModel? _consumeChannel;
    private AsyncEventingBasicConsumer? _consumer;
    private CancellationTokenSource? _consumeCts;
    private bool _isConsuming;
    private bool _isDisposed;

    // 死信队列配置
    private string _deadLetterExchange => $"{_config.ExchangeName}{_config.DeadLetterExchangeSuffix}";
    private string _deadLetterRoutingKey => $"{_config.RoutingKey}{_config.DeadLetterRoutingKeySuffix}";
    #endregion

    #region 事件定义(生产环境监控)
    /// <summary>
    /// 消费成功事件
    /// </summary>
    public event EventHandler<string>? ConsumeSucceeded;

    /// <summary>
    /// 消费失败事件(超过重试次数)
    /// </summary>
    public event EventHandler<string>? ConsumeFailed;

    /// <summary>
    /// 连接异常事件
    /// </summary>
    public event EventHandler<Exception>? ConnectionError;
    #endregion

    #region 构造函数
    /// <summary>
    /// 初始化生产级RabbitMQ客户端
    /// </summary>
    /// <param name="config">配置</param>
    /// <param name="logger">日志(生产环境必须传入)</param>
    public RabbitMqProductionClient(RabbitMqProductionConfig config, ILogger logger)
    {
        _config = config ?? throw new ArgumentNullException(nameof(config));
        _logger = logger ?? throw new ArgumentNullException(nameof(logger));
        _connectionPool = new ConcurrentDictionary<string, IConnection>();

        // 序列化配置(生产环境建议禁用循环引用)
        _jsonSettings = new JsonSerializerSettings
        {
            DateFormatString = "yyyy-MM-dd HH:mm:ss.fff",
            NullValueHandling = NullValueHandling.Ignore,
            ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
            Formatting = Formatting.None // 禁用格式化,减小消息体积
        };

        // 初始化发布信道
        InitPublishChannel();

        // 声明死信交换机和队列(生产环境必须)
        DeclareDeadLetterTopology();
    }
    #endregion

    #region 连接管理(集群支持+自动重连)
    /// <summary>
    /// 获取连接(支持集群节点切换)
    /// </summary>
    /// <returns></returns>
    private IConnection GetConnection()
    {
        var nodes = _config.Nodes.Split(',', StringSplitOptions.RemoveEmptyEntries)
            .Select(node => node.Trim())
            .ToList();

        foreach (var node in nodes)
        {
            var (host, port) = node.Split(':') is { Length: 2 } parts 
                ? (parts[0], int.Parse(parts[1])) 
                : (node, 5672);

            var connectionKey = $"{host}:{port}:{_config.VirtualHost}";
            if (_connectionPool.TryGetValue(connectionKey, out var connection) && connection.IsOpen)
            {
                return connection;
            }

            lock (_lockObj)
            {
                if (_connectionPool.TryGetValue(connectionKey, out connection) && connection.IsOpen)
                {
                    return connection;
                }

                try
                {
                    var factory = new ConnectionFactory
                    {
                        HostName = host,
                        Port = port,
                        UserName = _config.UserName,
                        Password = _config.Password,
                        VirtualHost = _config.VirtualHost,
                        RequestedHeartbeat = TimeSpan.FromSeconds(_config.HeartbeatSeconds),
                        ConnectionTimeout = _config.ConnectionTimeout,
                        AutomaticRecoveryEnabled = true, // 自动恢复连接
                        NetworkRecoveryInterval = TimeSpan.FromSeconds(10), // 恢复间隔
                        TopologyRecoveryEnabled = true, // 自动恢复拓扑
                        ClientProvidedName = $"{_config.ProducerService}-{Environment.MachineName}" // 客户端名称(便于RabbitMQ管控台识别)
                    };

                    connection = factory.CreateConnection();
                    _logger.Information($"RabbitMQ连接成功:{connectionKey}");

                    // 连接事件监听(生产环境监控必备)
                    connection.ConnectionShutdown += (s, e) =>
                    {
                        _logger.Warning($"RabbitMQ连接关闭:{e.ReplyText}");
                        _connectionPool.TryRemove(connectionKey, out _);
                        if (_isConsuming) _ = RestartConsumeAsync();
                    };
                    connection.CallbackException += (s, e) =>
                    {
                        _logger.Error(e.Exception, "RabbitMQ回调异常");
                        ConnectionError?.Invoke(this, e.Exception);
                        if (_isConsuming) _ = RestartConsumeAsync();
                    };
                    connection.ConnectionBlocked += (s, e) =>
                    {
                        _logger.Warning($"RabbitMQ连接被阻塞:{e.Reason}");
                        ConnectionError?.Invoke(this, new Exception($"连接被阻塞:{e.Reason}"));
                    };

                    _connectionPool[connectionKey] = connection;
                    return connection;
                }
                catch (Exception ex)
                {
                    _logger.Error(ex, $"RabbitMQ连接失败:{node}");
                    continue;
                }
            }
        }

        throw new Exception("所有RabbitMQ节点连接失败");
    }

    /// <summary>
    /// 初始化发布信道
    /// </summary>
    private void InitPublishChannel()
    {
        if (_publishChannel != null && _publishChannel.IsOpen) return;

        var connection = GetConnection();
        _publishChannel = connection.CreateModel();

        // 声明业务交换机(幂等操作,重复声明无影响)
        _publishChannel.ExchangeDeclare(
            exchange: _config.ExchangeName,
            type: _config.ExchangeType,
            durable: _config.Durable,
            autoDelete: false,
            arguments: new Dictionary<string, object>
            {
                {"x-message-ttl", _config.MessageTtl},
                {"x-max-length", _config.QueueMaxLength}
            });

        // 声明业务队列(绑定死信)
        _publishChannel.QueueDeclare(
            queue: _config.QueueName,
            durable: _config.Durable,
            exclusive: false,
            autoDelete: false,
            arguments: new Dictionary<string, object>
            {
                {"x-message-ttl", _config.MessageTtl},
                {"x-max-length", _config.QueueMaxLength},
                {"x-dead-letter-exchange", _deadLetterExchange},
                {"x-dead-letter-routing-key", _deadLetterRoutingKey},
                {"x-queue-mode", "lazy"} // 惰性队列:消息直接写入磁盘,减少内存占用(生产环境建议开启)
            });

        // 绑定队列到交换机
        _publishChannel.QueueBind(
            queue: _config.QueueName,
            exchange: _config.ExchangeName,
            routingKey: _config.RoutingKey);
    }

    /// <summary>
    /// 声明死信交换机和队列(生产环境必须)
    /// 用于存储消费失败超过重试次数的消息
    /// </summary>
    private void DeclareDeadLetterTopology()
    {
        var connection = GetConnection();
        using var channel = connection.CreateModel();

        // 声明死信交换机
        channel.ExchangeDeclare(
            exchange: _deadLetterExchange,
            type: _config.ExchangeType,
            durable: _config.Durable,
            autoDelete: false);

        // 声明死信队列
        channel.QueueDeclare(
            queue: $"{_config.QueueName}.dlq",
            durable: _config.Durable,
            exclusive: false,
            autoDelete: false,
            arguments: new Dictionary<string, object>
            {
                {"x-message-ttl", 86400000} // 死信消息保存24小时
            });

        // 绑定死信队列
        channel.QueueBind(
            queue: $"{_config.QueueName}.dlq",
            exchange: _deadLetterExchange,
            routingKey: _deadLetterRoutingKey);

        _logger.Information($"死信队列初始化完成:{_config.QueueName}.dlq");
    }

    /// <summary>
    /// 重启消费(连接断开后自动恢复)
    /// </summary>
    private async Task RestartConsumeAsync()
    {
        if (_isDisposed) return;

        _logger.Warning("开始重启RabbitMQ消费...");
        await Task.Delay(5000); // 延迟5秒,避免频繁重试

        try
        {
            StopConsume();
            _logger.Information("RabbitMQ消费重启成功");
        }
        catch (Exception ex)
        {
            _logger.Error(ex, "RabbitMQ消费重启失败,将在10秒后重试");
            await Task.Delay(10000);
            await RestartConsumeAsync();
        }
    }
    #endregion

    #region 消息发布(生产级可靠发布)
    /// <summary>
    /// 发布消息(同步,生产环境建议用异步)
    /// </summary>
    /// <typeparam name="T">业务数据类型</typeparam>
    /// <param name="message">消息体</param>
    /// <param name="routingKey">自定义路由键</param>
    /// <exception cref="ArgumentNullException"></exception>
    /// <exception cref="InvalidOperationException"></exception>
    public void Publish<T>(RabbitMqProductionMessage<T> message, string? routingKey = null)
    {
        PublishAsync(message, routingKey).Wait();
    }

    /// <summary>
    /// 发布消息(异步,生产环境推荐)
    /// 支持发布确认(生产环境建议开启)
    /// </summary>
    /// <typeparam name="T">业务数据类型</typeparam>
    /// <param name="message">消息体</param>
    /// <param name="routingKey">自定义路由键</param>
    /// <returns></returns>
    /// <exception cref="ArgumentNullException"></exception>
    /// <exception cref="InvalidOperationException"></exception>
    public async Task PublishAsync<T>(RabbitMqProductionMessage<T> message, string? routingKey = null)
    {
        if (_isDisposed) throw new InvalidOperationException("客户端已释放");
        if (message == null) throw new ArgumentNullException(nameof(message));
        if (!message.Validate()) throw new ArgumentException("消息无效", nameof(message));

        try
        {
            if (_publishChannel == null || !_publishChannel.IsOpen)
            {
                InitPublishChannel();
            }

            // 序列化消息(压缩可选,生产环境大消息建议压缩)
            var messageBody = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(message, _jsonSettings));

            // 消息属性(生产环境必须设置)
            var properties = _publishChannel.CreateBasicProperties();
            properties.DeliveryMode = 2; // 持久化
            properties.MessageId = message.MessageId;
            properties.CorrelationId = message.TraceId;
            properties.Timestamp = new AmqpTimestamp(Convert.ToInt64((message.SendTimeUtc - new DateTime(1970, 1, 1)).TotalSeconds));
            properties.Headers = new Dictionary<string, object>
            {
                {"ProducerService", message.ProducerService},
                {"SendTimeUtc", message.SendTimeUtc.ToString("o")}
            };

            // 开启发布确认(生产环境必须,确保消息到达交换机)
            _publishChannel.ConfirmSelect();

            await Task.Run(() =>
            {
                _publishChannel.BasicPublish(
                    exchange: _config.ExchangeName,
                    routingKey: routingKey ?? _config.RoutingKey,
                    mandatory: true, // 强制路由,失败触发Return事件
                    basicProperties: properties,
                    body: messageBody);

                // 等待确认(超时10秒)
                if (!_publishChannel.WaitForConfirms(TimeSpan.FromSeconds(10)))
                {
                    throw new Exception("消息发布未收到确认");
                }
            });

            _logger.Information($"消息发布成功 | MessageId:{message.MessageId} | TraceId:{message.TraceId}");
        }
        catch (Exception ex)
        {
            _logger.Error(ex, $"消息发布失败 | MessageId:{message.MessageId}");
            throw;
        }
    }
    #endregion

    #region 消息消费(生产级持续消费)
    /// <summary>
    /// 启动持续消费(生产环境核心方法)
    /// </summary>
    /// <typeparam name="T">业务数据类型</typeparam>
    /// <param name="handleFunc">消费逻辑(业务代码)</param>
    /// <param name="autoAck">是否自动确认(生产环境建议false)</param>
    /// <returns></returns>
    public async Task StartConsumeAsync<T>(Func<RabbitMqProductionMessage<T>, Task> handleFunc, bool autoAck = false)
    {
        if (_isConsuming)
        {
            _logger.Warning("消费已启动,无需重复调用");
            return;
        }

        if (handleFunc == null) throw new ArgumentNullException(nameof(handleFunc));

        _isConsuming = true;
        _consumeCts = new CancellationTokenSource();

        try
        {
            var connection = GetConnection();
            _consumeChannel = connection.CreateModel();
            _consumeChannel.BasicQos(0, _config.PrefetchCount, false); // 限流:每次最多处理PrefetchCount条消息

            _consumer = new AsyncEventingBasicConsumer(_consumeChannel);
            _consumer.Received += async (sender, args) =>
            {
                if (_consumeCts.Token.IsCancellationRequested) return;

                var messageId = args.BasicProperties.MessageId ?? Guid.NewGuid().ToString("N");
                var traceId = args.BasicProperties.CorrelationId ?? Guid.NewGuid().ToString("N");

                try
                {
                    // 反序列化消息
                    var messageBody = Encoding.UTF8.GetString(args.Body.ToArray());
                    var message = JsonConvert.DeserializeObject<RabbitMqProductionMessage<T>>(messageBody, _jsonSettings);
                    if (message == null || !message.Validate())
                    {
                        _logger.Warning($"消息无效,直接丢弃 | MessageId:{messageId}");
                        _consumeChannel.BasicNack(args.DeliveryTag, false, false);
                        ConsumeFailed?.Invoke(this, messageId);
                        return;
                    }

                    // 获取重试次数
                    var retryCount = args.BasicProperties.Headers?.ContainsKey("RetryCount") == true
                        ? Convert.ToInt32(args.BasicProperties.Headers["RetryCount"])
                        : 0;

                    // 幂等性校验(生产环境必须,防止重复消费)
                    if (await CheckIdempotentAsync(message.MessageId))
                    {
                        _logger.Information($"消息已消费,跳过 | MessageId:{messageId} | TraceId:{traceId}");
                        _consumeChannel.BasicAck(args.DeliveryTag, false);
                        return;
                    }

                    // 执行业务消费逻辑
                    await handleFunc(message);

                    // 手动确认消息
                    if (!autoAck)
                    {
                        _consumeChannel.BasicAck(args.DeliveryTag, false);
                    }

                    // 记录幂等标识
                    await RecordIdempotentAsync(message.MessageId);

                    _logger.Information($"消息消费成功 | MessageId:{messageId} | TraceId:{traceId}");
                    ConsumeSucceeded?.Invoke(this, messageId);
                }
                catch (Exception ex)
                {
                    _logger.Error(ex, $"消息消费失败 | MessageId:{messageId} | TraceId:{traceId}");

                    var retryCount = args.BasicProperties.Headers?.ContainsKey("RetryCount") == true
                        ? Convert.ToInt32(args.BasicProperties.Headers["RetryCount"]) + 1
                        : 1;

                    if (retryCount <= _config.MaxRetryCount)
                    {
                        // 更新重试次数,重新入队
                        args.BasicProperties.Headers ??= new Dictionary<string, object>();
                        args.BasicProperties.Headers["RetryCount"] = retryCount;
                        _consumeChannel.BasicNack(args.DeliveryTag, false, true);
                        _logger.Warning($"消息重试 {retryCount}/{_config.MaxRetryCount} | MessageId:{messageId}");
                    }
                    else
                    {
                        // 超过重试次数,进入死信队列
                        _consumeChannel.BasicNack(args.DeliveryTag, false, false);
                        _logger.Error($"消息超过最大重试次数,进入死信队列 | MessageId:{messageId}");
                        ConsumeFailed?.Invoke(this, messageId);
                    }
                }
            };

            // 处理消息无法路由的情况
            _consumer.HandleReturn += (sender, args) =>
            {
                var messageId = args.BasicProperties?.MessageId ?? "未知";
                _logger.Error($"消息无法路由 | MessageId:{messageId} | 路由键:{args.RoutingKey}");
                ConsumeFailed?.Invoke(this, messageId);
            };

            // 开始消费(永久阻塞)
            _consumeChannel.BasicConsume(
                queue: _config.QueueName,
                autoAck: autoAck,
                consumer: _consumer);

            _logger.Information("RabbitMQ消费已启动,持续监听队列...");

            // 阻塞当前任务,保持消费线程存活
            await Task.Delay(Timeout.Infinite, _consumeCts.Token);
        }
        catch (OperationCanceledException)
        {
            _logger.Information("消费已取消");
        }
        catch (Exception ex)
        {
            _logger.Error(ex, "消费启动失败");
            throw;
        }
    }

    /// <summary>
    /// 停止消费(仅在程序退出时调用)
    /// </summary>
    public void StopConsume()
    {
        if (!_isConsuming) return;

        _isConsuming = false;
        _consumeCts?.Cancel();
        _consumer?.Model?.BasicCancel(_consumer.ConsumerTag);
        _consumeChannel?.Close();
        _consumeChannel?.Dispose();
        _consumeChannel = null;

        _logger.Information("RabbitMQ消费已停止");
    }

    #region 幂等性实现(生产环境必须,以下为示例,需根据业务调整)
    /// <summary>
    /// 幂等性校验(检查消息是否已消费)
    /// </summary>
    /// <param name="messageId">消息ID</param>
    /// <returns></returns>
    private async Task<bool> CheckIdempotentAsync(string messageId)
    {
        // 生产环境实现:
        // 1. 基于Redis:EXISTS {messageId}
        // 2. 基于数据库:查询消费记录表
        await Task.CompletedTask;
        return false;
    }

    /// <summary>
    /// 记录幂等标识(标记消息已消费)
    /// </summary>
    /// <param name="messageId">消息ID</param>
    /// <returns></returns>
    private async Task RecordIdempotentAsync(string messageId)
    {
        // 生产环境实现:
        // 1. 基于Redis:SET {messageId} 1 EX 86400
        // 2. 基于数据库:插入消费记录表
        await Task.CompletedTask;
    }
    #endregion
    #endregion

    #region 资源释放(生产环境必须)
    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    protected virtual void Dispose(bool disposing)
    {
        if (_isDisposed) return;

        if (disposing)
        {
            // 停止消费
            StopConsume();
            _consumeCts?.Dispose();

            // 释放信道
            _publishChannel?.Close();
            _publishChannel?.Dispose();

            // 释放连接池
            foreach (var connection in _connectionPool.Values)
            {
                if (connection.IsOpen) connection.Close();
                connection.Dispose();
            }
            _connectionPool.Clear();

            _logger.Information("RabbitMQ客户端资源已释放");
        }

        _isDisposed = true;
    }

    ~RabbitMqProductionClient()
    {
        Dispose(false);
    }
    #endregion
}

三、生产环境使用示例

1. 生产者示例
cs 复制代码
using System;
using System.Threading.Tasks;
using Serilog;

class ProducerExample
{
    static async Task Main(string[] args)
    {
        // 1. 配置日志
        var logger = SerilogConfig.CreateProductionLogger();

        // 2. 配置RabbitMQ
        var config = new RabbitMqProductionConfig
        {
            Nodes = "rabbitmq-node1:5672,rabbitmq-node2:5672", // 集群节点
            UserName = "prod_user",
            Password = "prod_password",
            ExchangeName = "order.exchange",
            QueueName = "order.create.queue",
            RoutingKey = "order.create",
            PrefetchCount = 10,
            MaxRetryCount = 3
        };

        // 3. 创建客户端
        using var client = new RabbitMqProductionClient(config, logger);

        // 4. 发布消息
        for (int i = 1; i <= 1000; i++)
        {
            var message = new RabbitMqProductionMessage<OrderDto>
            {
                Data = new OrderDto
                {
                    OrderId = Guid.NewGuid().ToString("N"),
                    UserId = "user_001",
                    Amount = i * 10,
                    CreateTime = DateTime.UtcNow
                },
                ProducerService = "OrderService",
                TraceId = Guid.NewGuid().ToString("N")
            };

            await client.PublishAsync(message);
            await Task.Delay(100); // 每秒发布10条
        }

        Console.WriteLine("消息发布完成");
        Console.ReadKey();
    }
}

// 业务DTO
public class OrderDto
{
    public string OrderId { get; set; } = string.Empty;
    public string UserId { get; set; } = string.Empty;
    public decimal Amount { get; set; }
    public DateTime CreateTime { get; set; }
}
2. 消费者示例(Windows 服务 / Linux 守护进程)
cs 复制代码
using System;
using System.Threading.Tasks;
using Serilog;

class ConsumerExample
{
    static async Task Main(string[] args)
    {
        // 1. 配置日志
        var logger = SerilogConfig.CreateProductionLogger();

        // 2. 配置RabbitMQ
        var config = new RabbitMqProductionConfig
        {
            Nodes = "rabbitmq-node1:5672,rabbitmq-node2:5672",
            UserName = "prod_user",
            Password = "prod_password",
            ExchangeName = "order.exchange",
            QueueName = "order.create.queue",
            RoutingKey = "order.create",
            PrefetchCount = 10,
            MaxRetryCount = 3
        };

        // 3. 创建客户端
        using var client = new RabbitMqProductionClient(config, logger);

        // 4. 订阅监控事件
        client.ConsumeSucceeded += (s, messageId) =>
        {
            // 生产环境:上报监控平台(如Prometheus/Grafana)
            logger.Information($"监控-消费成功:{messageId}");
        };
        client.ConsumeFailed += (s, messageId) =>
        {
            // 生产环境:发送告警(钉钉/邮件/短信)
            logger.Error($"监控-消费失败:{messageId}");
        };
        client.ConnectionError += (s, ex) =>
        {
            logger.Error(ex, "监控-连接异常");
        };

        // 5. 启动持续消费
        await client.StartConsumeAsync<RabbitMqProductionMessage<OrderDto>>(async (message) =>
        {
            // 生产环境业务逻辑:
            // 1. 更新订单状态
            // 2. 扣减库存
            // 3. 发送短信通知
            logger.Information($"处理订单:{message.Data.OrderId} | 金额:{message.Data.Amount}");
            await Task.Delay(100); // 模拟业务处理
        }, autoAck: false);

        // 6. 阻止程序退出(生产环境作为服务运行时无需)
        Console.WriteLine("消费者已启动,按任意键退出...");
        Console.ReadKey();

        // 7. 停止消费(程序退出时调用)
        client.StopConsume();
    }
}
相关推荐
回家路上绕了弯1 天前
分布式锁原理深度解析:从理论到实践
分布式·后端
heartbeat..1 天前
深入理解 Redisson:分布式锁原理、特性与生产级应用(Java 版)
java·分布式·线程·redisson·
ha_lydms1 天前
Kafka如何提高读写效率
分布式·kafka
武子康1 天前
Java-195 RabbitMQ BlockingQueue 手搓“消息中间件”雏形:生产者-消费者模型到企业级 MQ 差在哪
java·分布式·架构·消息队列·rabbitmq·java-rabbitmq·mq
song5011 天前
鸿蒙 Flutter 复杂表单验证:自定义规则与联动逻辑
分布式·python·flutter·ci/cd·分类
音符犹如代码1 天前
深入解析 Apollo:微服务时代的配置管理利器
java·分布式·后端·微服务·中间件·架构
招风的黑耳1 天前
拆解基于SpringCloud社区团购项目:微服务划分与分布式事务实战
分布式·spring cloud·微服务