从 MSMQ 中删除了多条消息

Multiple messages removed from MSMQ

我有一个运行在 WCF 和 MSMQ 上的特定服务。 一切正常,但我们有这样的要求,即如果在处理一项工作期间发生意外情况,则不应影响任何其他工作。 该服务被设计为健壮的,而且确实如此。我们在两年的运营中从未遇到过崩溃,但最近我们的客户喜欢终止服务流程并抱怨不止一项工作丢失。

为了调查,我添加了一个计时器,它每 200 毫秒跟踪一次队列的内容,并发现了一些意想不到的东西。 处理请求时,WCF 从队列中移除多个消息。 这是相关事件的 smartinspec 跟踪(中间列中的数字是线程 ID):

似乎总是在服务进程的某个地方缓存一条消息。 我一直在查看 WCF 文档,但没有找到任何对此行为的引用 我能做些什么来防止这种缓冲,或者你能给我推荐一些相关文章吗?

这是服务 class:

[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Single)]
 public class TheService : ITheService
 {
   private readonly ITraceFacade trace = TraceFactory.Resolve();//for tracing

   public ClientCodeWrapper clientCodeWrapper { get; set; }// a wrapper for libraries written by our client. it's instantiated and set in the OnStart method of the service host class

   public void ProcessJob(long jobId)
   {
      using (this.trace.ActivityScope(string.Format(CultureInfo.InvariantCulture, "The Service.ProcessJob({0})", jobId)))
       {        
         this.clientCodeWrapper.ProcessJob(jobId);        
       }
    }    
 }

这是我的服务配置

<system.serviceModel>
  <bindings>
    <netMsmqBinding>
      <binding name="MsmqBindingNonTransactionalNoSecurity" exactlyOnce="false">
        <security mode="None"/>
      </binding>
    </netMsmqBinding>
  </bindings>

  <services>
    <service name="TheService">
      <host>
        <baseAddresses>
          <add baseAddress="http://localhost:8080/TheServiceIn"   />           
        </baseAddresses>
      </host>           
      <endpoint address="net.msmq://localhost/private/TheServiceIn"  
              binding="netMsmqBinding"
              bindingConfiguration="MsmqBindingNonTransactionalNoSecurity" 
              contract="ITheService">         
        <identity>
          <dns value="localhost"/>
        </identity>
      </endpoint>       

      <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
    </service>
  </services>
</system.serviceModel>

你所看到的似乎是我意料之中的。确实WCF可以读取队列的多条消息进行处理。通常,这不是问题,对于事务队列,这绝对不是问题(因为每个单独的事务只会在消息处理完成后提交,否则事务将中止并将消息返回到队列) .

所以基本上,您选择不以通过禁用事务和使用非事务队列来避免丢失消息的方式处理消息。基本上你告诉 MSMQ 和 WCF 偶尔丢失消息是完全可以的。

考虑一下如果您的机器(或 MSMQ 服务)崩溃会发生什么:您不会只失去一份工作;你会失去所有这些,因为消息不会被保留。