• 2.6.8 Masstransit异常处理和总结


    一、异常处理

    1.1异常与重试

     Exception

    public class SubmitOrderConsumer :
        IConsumer<SubmitOrder>
    {
        public Task Consume(ConsumeContext<SubmitOrder> context)
        {
            throw new Exception("Very bad things happened");
        }
    }
    

    UseMessageRetry  

    var sessionFactory = CreateSessionFactory();
     
    var busControl = Bus.Factory.CreateUsingRabbitMq(cfg =>
    {
        cfg.Host("rabbitmq://localhost/");
     
        cfg.ReceiveEndpoint("submit-order", e =>
        {
            e.UseMessageRetry(r => r.Immediate(5));
     
            e.Consumer(() => new SubmitOrderConsumer(sessionFactory));
        });
    });

    1.2重试配置

     

    // 立即重试:一共连续重试10次
    ep.UseMessageRetry(r => r.Immediate(10));
     
    // 间隔重试:一共重试10次,每次间隔10秒
    ep.UseMessageRetry(r => r.Interval(10, TimeSpan.FromSeconds(10)));
     
    // 多个间隔重试:5秒后第一次,5+10秒后第二次,5+10+15秒后第三次
    ep.UseMessageRetry(r => r.Intervals(TimeSpan.FromSeconds(5), TimeSpan.FromSeconds(10), TimeSpan.FromSeconds(15)));
     
    // 指数级间隔重试:共10次,每次间隔:当前重试次数 * 60秒
    ep.UseMessageRetry(r => r.Exponential(10, TimeSpan.FromSeconds(60), TimeSpan.FromHours(24), TimeSpan.FromSeconds(60)));
     
    // 每次叠加50秒
    ep.UseMessageRetry(r => r.Incremental(10, TimeSpan.FromSeconds(10), TimeSpan.FromSeconds(50)));

    1.3重试条件

    e.UseMessageRetry(r => 
    {
        r.Handle<ArgumentNullException>();
        r.Ignore(typeof(InvalidOperationException), typeof(InvalidCastException));
        r.Ignore<ArgumentException>(t => t.ParamName == "orderTotal");
    }); 

    过滤某些异常类型不进行重试

    1.4重新投递信息

    cfg.ReceiveEndpoint("submit-order", e =>
    {
        e.UseScheduledRedelivery(r => r.Intervals(TimeSpan.FromMinutes(5), TimeSpan.FromMinutes(15), TimeSpan.FromMinutes(30)));
        e.UseMessageRetry(r => r.Immediate(5));
        e.Consumer(() => new SubmitOrderConsumer(sessionFactory));
    });

    消息冲队列移除之后,在一定时间之后重新投入消息队列。需要配置调度模块(scheduling)

    1.5信箱

    cfg.ReceiveEndpoint("submit-order", e =>
    {
        e.UseScheduledRedelivery(r => r.Intervals(TimeSpan.FromMinutes(5), TimeSpan.FromMinutes(15), TimeSpan.FromMinutes(30)));
        e.UseMessageRetry(r => r.Immediate(5));
        e.UseInMemoryOutbox();
     
        e.Consumer(() => new SubmitOrderConsumer(sessionFactory));
    });

    有些消息是在 consume 方法中发送或发布的,如果在发送之后 consume 中产生了异常,那原来发出去的消息就需要撤回,如果使用信箱之后,在 consume 中要发布/发送的消息就会先暂存在内存中直到 consume 方法成功之后才真正发出去

    二、其他

    2.1Fault

    public interface Fault<T>
        where T : class
    {
        Guid FaultId { get; }
        Guid? FaultedMessageId { get; }
        DateTime Timestamp { get; }
        ExceptionInfo[] Exceptions { get; }
        HostInfo Host { get; }
        T Message { get; }
    }

    Fault 消息在异常的时候会发布出来

    2.2Consuming Faults

    public class DashboardFaultConsumer :
        IConsumer<Fault<SubmitOrder>>
    {
        public async Task Consume(ConsumeContext<Fault<SubmitOrder>> context)
        {
            // update the dashboard
        }
    }

    Fault 消息也是可以进行订阅的

    2.3Error Pipe

    cfg.ReceiveEndpoint("input-queue", ec =>
    {
        ec.DiscardFaultedMessages();
    });

    默认情况下错误的消息会被投递到了 _error 队列,可以配置直接抛弃错误信息

    2.4Dead-Letter Pipe

    cfg.ReceiveEndpoint("input-queue", ec =>
    {
        ec.DiscardSkippedMessages();
    });

    死信队列:没有消费者的消息会被移到 _skipped 队列,但可以配置为不移到 _skipped 队列

    三、高级功能

    • 持久化
    • Saga 事件串
    • 调度
    • Courier 最终一致性
    • 监控
  • 相关阅读:
    ArrayList removeRange方法分析
    LinkedHashMap源码分析(基于JDK1.6)
    LinkedList原码分析(基于JDK1.6)
    TreeMap源码分析——深入分析(基于JDK1.6)
    51NOD 2072 装箱问题 背包问题 01 背包 DP 动态规划
    51 NOD 1049 最大子段和 动态规划 模板 板子 DP
    51NOD 1006 最长公共子序列 Lcs 动态规划 DP 模板题 板子
    8月20日 训练日记
    CodeForces
    CodeForces
  • 原文地址:https://www.cnblogs.com/duyao/p/14329270.html
Copyright © 2020-2023  润新知