我应该如何从数据库表中实现多线程队列?

时间:2011-12-30 21:31:28

标签: .net message-queue

我的流程如下:

  1. 用户登录Web应用程序,这会将一个条目删除到UserQueue表
  2. Windows服务每隔x秒轮询此表并处理每个项目
  3. 处理后,该项目将从UserQueue表中删除
  4. 这一切都适用于顺序处理,但我担心长时间运行的任务可能会阻止所有其他用户的队列(这对Web应用程序来说也是一个问题)。

    我认为.NET中的BlockingCollection将项目保存在内存中然后处理它们但我不能保证UserQueue表中的一行不会多次被放入该集合中(由于非唯一性质) of BlockingCollection)除非我使用数据库标志(例如,BeingProcessed = true)。我并不热衷于数据库标志,因为如果我的服务因任何原因而被停止,它可能会将未处理的项目留在表中,并且存在BeingProcessed = true。

    我是否缺少更为标准的方法,或者我应该考虑使用Quartz.net或类似方法?

2 个答案:

答案 0 :(得分:1)

基本技巧是使用带有日期的测试和设置,而不仅仅是一个简单的布尔值。这是你如何做到的。

假设您的UserQueue表非常简单。这样的事情,目前:

create table UserQueue (id integer primary key, description varchar not null)

到目前为止,这么好。但是我们想要安全地抓住任务并用它做点什么。

首先,让我们稍微改变架构:

create table UserQueue (id integer primary key, description varchar not null,
                        dtLocked datetime null)

现在,我们只需遵循一个简单的程序:

  1. 寻找我们可以通过select * from UserQueue limit 1
  2. 申请的工作
  3. 尝试锁定它,将时间戳设置为NOW() ,其当前为空,例如update UserQueue set dtLocked = NOW() where id = @id and dtLocked is null
  4. 仅在至少更新了一行时才进行。
  5. 因为我们现在使用datetime进行锁定,所以我们可以通过简单的更新语句定期清除死亡任务,该语句删除超过一定时间(例如五分钟)的锁定。

    作为奖励,此设计可让您一次安全地处理多个任务,因此您可以通过简单地激活更多线程来消除任何阻止用户任务的机会。

答案 1 :(得分:0)

虽然您的问题可能会受益于数据库事务,但我不确定您是否会因为排队的相同项目而长时间运行的进程获得更多收益。对于那种情况,我建议找一个对提交的数据有意义的更好的主键,以便排队框架按顺序应用影响该行的数据。我还建议查看现有的排队框架,如Microsoft Queuing或IBM的MQ(不可否认,我对排队框架并不十分熟悉)。