Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/23.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# Rebus中某一消息类型的串行处理_C#_.net_Message Bus_Rebus - Fatal编程技术网

C# Rebus中某一消息类型的串行处理

C# Rebus中某一消息类型的串行处理,c#,.net,message-bus,rebus,C#,.net,Message Bus,Rebus,我们有一个与第三方Web服务对话的REBS消息处理程序。由于我们无法直接控制的原因,此WCF服务经常引发异常,因为它在自己的数据库中遇到数据库死锁。然后,Rebus将尝试处理此消息五次,这在大多数情况下意味着这五次中的一次是幸运的,不会出现死锁。但经常发生的情况是,一条消息在死锁后确实会死锁,并最终进入我们的错误队列 除了解决僵局的根源(这将是一个长期目标)之外,我可以想到两个选择: 继续尝试仅使用此特定消息类型,直到成功。我最好能够设置一个超时,这样“如果有五个死锁,那么在5分钟内再试一次”,

我们有一个与第三方Web服务对话的REBS消息处理程序。由于我们无法直接控制的原因,此WCF服务经常引发异常,因为它在自己的数据库中遇到数据库死锁。然后,Rebus将尝试处理此消息五次,这在大多数情况下意味着这五次中的一次是幸运的,不会出现死锁。但经常发生的情况是,一条消息在死锁后确实会死锁,并最终进入我们的错误队列

除了解决僵局的根源(这将是一个长期目标)之外,我可以想到两个选择:

  • 继续尝试仅使用此特定消息类型,直到成功。我最好能够设置一个超时,这样“如果有五个死锁,那么在5分钟内再试一次”,而不是通过不断地尝试来阻塞进程。我已经做了一个Thread.Sleep(random)来传播一些信息,但是五次尝试后它仍然会放弃

  • 将此特定消息类型发送到另一个队列,该队列只有一个工作进程来处理该消息,因此这是串行发生的,而不是并行发生的。我们当前的配置使用8个工作线程,但这只会使死锁情况变得更糟,因为webservice现在会被并发调用,消息会相互阻碍

  • 选项2是我的偏好,但我不确定这是否可行。我们在接收端的配置目前如下所示:

    var adapter = new Rebus.Ninject.NinjectContainerAdapter(this.Kernel);
    
    var bus = Rebus.Configuration.Configure.With(adapter)
        .Logging(x => x.Log4Net())
       .Transport(t => t.UseMsmqAndGetInputQueueNameFromAppConfig())
       .MessageOwnership(d => d.FromRebusConfigurationSection())
       .CreateBus().Start();
    
    public void Handle(TryMakeWebServiceCall message)
    {
        try
        {
            var result = client.MakeWebServiceCall(whatever);
    
            bus.Reply(new ResponseWithTheResult{ ... });
        }
        catch(Exception e)
        {
            Data.FailedAttempts++;
    
            if (Data.FailedAttempts < 10)
            {
                bus.Defer(TimeSpan.FromSeconds(1), message);
                return;
            }
    
            // oh no! we failed 10 times... this is probably where we'd
            // go and do something like this:
            emailService.NotifyAdministrator("Something went wrong!");
        }
    }
    
    以及接收端的.config:

    基本上,我要寻找的是以下几点:

    <rebus workers="8">
      <input name="app.msg.input" error="app.msg.error" />
      <input name="another.input.queue" error="app.msg.error" />
    </rebus>
    
    
    

    关于如何处理我的需求,有什么建议吗?

    我建议您利用saga和Rebus的超时服务来实施适合您需要的重试策略。这样,在支持REBS的web服务facade中,您可以执行以下操作:

    var adapter = new Rebus.Ninject.NinjectContainerAdapter(this.Kernel);
    
    var bus = Rebus.Configuration.Configure.With(adapter)
        .Logging(x => x.Log4Net())
       .Transport(t => t.UseMsmqAndGetInputQueueNameFromAppConfig())
       .MessageOwnership(d => d.FromRebusConfigurationSection())
       .CreateBus().Start();
    
    public void Handle(TryMakeWebServiceCall message)
    {
        try
        {
            var result = client.MakeWebServiceCall(whatever);
    
            bus.Reply(new ResponseWithTheResult{ ... });
        }
        catch(Exception e)
        {
            Data.FailedAttempts++;
    
            if (Data.FailedAttempts < 10)
            {
                bus.Defer(TimeSpan.FromSeconds(1), message);
                return;
            }
    
            // oh no! we failed 10 times... this is probably where we'd
            // go and do something like this:
            emailService.NotifyAdministrator("Something went wrong!");
        }
    }
    
    您可以在其中
    StoreInMemory
    StoreInSqlServer
    StoreInMongoDb
    StoreInRavenDb
    ,或
    使用外部TimeoutManager

    如果您选择(1),您需要检查Rebus代码并自行构建—它基本上只是一个可配置的、支持Topshelf的控制台应用程序,其中包含一个Rebus端点


    如果您需要更多帮助,请告诉我-
    总线。延迟
    是您的系统变得很棒的地方,并且将能够克服所有导致其他系统崩溃的小故障:)

    好的,酷!明天我一定要看一看传奇故事。我没有立即看到如何配置Saga状态的存储位置(我们可能使用sqlserver),但我相信我可以在某个地方找到它。谢谢我会让你知道这对我是否有效。编辑:已找到位置:)我可以在这里看到一些增长潜力,因为此Web服务用于下订单,我们向客户承诺,如果他们在某个时间之前下订单,他们将在第二天交付。使用这种方法,我们可以开始发送恐慌性电子邮件/短信,以防“截止日期”临近,仍然有消息需要处理。我已经尝试过这样做,我已经走了很长的路,但我遇到了一个问题。当出现
    bus.Defer
    时,它会序列化我定义的
    ISagaData
    类,但在反序列化后,Newtonsoft.Json声明它无法加载在其中定义类型的程序集。消息内容(在SQL Server中):
    {“$type”:“CeyennePOS.Tasks.MQ.ExternalOrderSagaData,CeyennePOS.Tasks.MQ”,“OrderID”:100,“尝试次数”:1,“Id”:“4b758670-7f39-4e51-8502-85a27a34e933”,“修订版”:1}
    。这个程序集是一个用
    assembly.LoadFile
    加载的插件。顺便说一句,当我使用始终加载的“核心”程序集而不是动态加载的程序集时,它确实可以工作。问题是,我可以肯定地知道,在设置Rebus
    IBus
    时,插件程序集已经加载。所以我不知道为什么找不到。我宁愿在插件程序集中定义saga类型,这样只有那些插件才依赖于Rebus。在bus.Defer调用期间,您创建了一个新的消息实例,而不是从方法参数传递原始消息变量,这有什么特殊原因吗?
    Configure.With(...)
        .(...)
        .Timeouts(t => // configure it here)