C# 多个使用者有条件地处理和删除MSMQ队列中的消息

C# 多个使用者有条件地处理和删除MSMQ队列中的消息,c#,asp.net,.net,message-queue,msmq,C#,Asp.net,.net,Message Queue,Msmq,我发现了这一点,但我的情况有点不同 我有一个ASP.NET应用程序,它生成长时间运行的任务,这些任务应该由许多后台进程(Windows服务)处理。大多数任务都是相似的,可以由大多数任务运行者处理。由于客户端应用程序的版本不同(其中任务由用户生成),某些任务只能由特定版本的任务运行程序处理。web服务器不知道任务的类型。它只是使用MSMQ将所有任务发送到同一队列 如果任务进入队列,下一个空闲任务运行者应该接收该任务,决定他是否可以处理此类任务,从队列中删除该任务并运行该任务 如果接收消息的运行程序

我发现了这一点,但我的情况有点不同

我有一个ASP.NET应用程序,它生成长时间运行的任务,这些任务应该由许多后台进程(Windows服务)处理。大多数任务都是相似的,可以由大多数任务运行者处理。由于客户端应用程序的版本不同(其中任务由用户生成),某些任务只能由特定版本的任务运行程序处理。web服务器不知道任务的类型。它只是使用MSMQ将所有任务发送到同一队列

如果任务进入队列,下一个空闲任务运行者应该接收该任务,决定他是否可以处理此类任务,从队列中删除该任务并运行该任务

如果接收消息的运行程序无法处理此类任务,则应将消息放回队列,以便其他运行程序可以查看消息

我尝试使用事务实现条件接收,如果任务的格式错误,我可以中止该事务:

transaction.Begin();
var msg = queue.Receive(TimeSpan.FromSeconds(1000), transaction);
if (CanHandle(msg))
{
    transaction.Commit();
    // handle
}
else
{
    transaction.Abort();
}
这似乎是可行的,但我不知道这是否是最好的方法

这个解决方案的另一个问题是,如果没有其他自由奔跑者可以处理这个消息,我会一次又一次地收到它

是否有一种方法可以仅使用MSMQ解决此问题?整个任务数据已存储在SQL数据库中。任务运行程序通过HTTP API访问任务数据(这就是我排除SQLServerServiceBroker这样的解决方案的原因)。发送到消息队列的数据只是用于标识作业的元数据


如果纯MSMQ不是正确的工具,我可以使用MassTransit解决问题吗(我不喜欢必须为它安装并运行额外的MassTransit RuntimeServices+SQL db这一事实)?其他建议?

您能创建另一个队列吗?如果是,那么我将创建多个队列。像GenericTaskQ一样,它将包含所有的任务,然后是xTaskQ和yTaskQ。现在,您的xTaskRunner将从通用队列中选择任务,如果无法处理它,则将其放入yTaskQ(或任何适当的q)。yTaskRunner也是如此,如果它无法处理消息,请将其放入xTaskQueue。x和y TaskRunner应该始终首先查找各自的队列,如果没有队列,则查看genericq


如果您不能创建多个Q,请使用消息(任务)标签(应该是唯一的,我们通常使用GUID)来记住任务运行者已经看到并且无法处理的任务。在实际接收消息之前,还可以使用Peek检查此消息是否已被寻址。

是否可以创建另一个队列?如果是,那么我将创建多个队列。像GenericTaskQ一样,它将包含所有的任务,然后是xTaskQ和yTaskQ。现在,您的xTaskRunner将从通用队列中选择任务,如果无法处理它,则将其放入yTaskQ(或任何适当的q)。yTaskRunner也是如此,如果它无法处理消息,请将其放入xTaskQueue。x和y TaskRunner应该始终首先查找各自的队列,如果没有队列,则查看genericq


如果您不能创建多个Q,请使用消息(任务)标签(应该是唯一的,我们通常使用GUID)来记住任务运行者已经看到并且无法处理的任务。在实际接收消息之前,还可以使用Peek检查此消息是否已被寻址。

您使用MSMQ的方式实际上绕过了该技术的一些基本功能。如果读卡器无法普遍处理队列消息,则会导致相当大的系统性能损失,其中许多任务处理服务在请求任务时可能会空手返回。在极端情况下,想象一下,如果只有一个服务可以执行任务类型“A”,会发生什么情况。如果该服务关闭,并且从队列中拉出的第一个任务是类型“A”,那么整个系统将关闭

我建议采用以下两种方法之一:

  • 利用多个队列,如每个任务版本一个队列。将任务检索隐藏在API或其他服务后面。您的服务可以从一个或多个任务类型请求任务,或者您甚至可以允许任何操作。然后,API将负责确定从哪个队列中提取(即映射到特定的任务类型,随机选择一个,进行某种循环机器人训练,等等)
  • 选择不同的存储技术而不是排队。如果您编写的SQL足够好,那么关系数据库就可以胜任这项任务。你只需要表现得非常小心,以免出现死锁

  • 您使用MSMQ的方式实际上绕过了该技术的一些基本功能。如果读卡器无法普遍处理队列消息,则会导致相当大的系统性能损失,其中许多任务处理服务在请求任务时可能会空手返回。在极端情况下,想象一下,如果只有一个服务可以执行任务类型“A”,会发生什么情况。如果该服务关闭,并且从队列中拉出的第一个任务是类型“A”,那么整个系统将关闭

    我建议采用以下两种方法之一:

  • 利用多个队列,如每个任务版本一个队列。将任务检索隐藏在API或其他服务后面。您的服务可以从一个或多个任务类型请求任务,或者您甚至可以允许任何操作。然后,API将负责确定从哪个队列中提取(即映射到特定的任务类型,随机选择一个,进行某种循环机器人训练,等等)
  • 选择不同的存储技术而不是排队。如果您编写的SQL足够好,那么关系数据库就可以胜任这项任务。你只需要表现得非常小心,以免出现死锁
  • 谢谢你的回答。如果