3

我正在使用 beanstalkd 的 Perl 客户端。我需要一种简单的方法来避免两次将相同的工作排入队列。

我需要的东西基本上需要等到有 K 个元素,然后将它们组合在一起。为了做到这一点,我有制片人:

insert item(s) into DB
insert a queue item into beanstalkd

和消费者:

while ( 1 ) {
   beanstalkd.retrieve
   if ( DB items >= K )
       func_to_process_all_items
   kill job
}

这与请求/处理的数量呈线性关系,但在以下情况下:

insert 1 item
... repeat many times ...
insert 1 item

假设所有这些插入发生在检索作业之前,这将添加 N 个队列项,它会执行以下操作:

check DB, process N items
check DB, no items
... many times ...
check DB, no items

有没有更聪明的方法来做到这一点,以便它不会不必要地插入/处理以后的作业请求?

4

2 回答 2

2

我有一个相关的要求。我只想在几分钟内处理一次特定的作业,但生产者可以将同一作业的多个实例排队。我使用 memcache 存储作业标识符并将密钥的到期时间设置为几分钟。

当工作人员尝试将作业标识符添加到内存缓存时,只有第一个会成功 - 如果添加作业 ID 失败,工作人员将删除该作业。几分钟后,密钥从 memcache 中过期,可以再次处理作业。

不是特别优雅,但它确实有效。

于 2011-02-08T10:53:48.813 回答
1

这对你有用吗?:

  1. 创建两个 Tubes “buffer” 和 “live”。您的制作人总是只添加到“缓冲”管中。
  2. 创建两个工人,一个监视“缓冲区”,另一个监视调用阻塞reserve()调用的“实时”
  3. 每当“缓冲区”工作人员保留返回时,如果少于 K 个项目,它就会埋葬工作。如果正好有 K 个,那么它会“踢”所有 K 个工作并将它们转移到“实时”管中。
  4. “实时”观察者现在将自行返回reserve()

您只需要注意作业不会从隐藏状态返回到缓冲区队列。执行此操作的故障安全方法可能是删除它,然后将其添加到实时状态。

两个单独的队列仅用于更清洁的分离。您可以对单个队列执行相同的操作,方法是隐藏所有作业,直到有 K-1 个作业,然后在第 K 个作业到达时,将所有作业踢活。

于 2009-12-24T04:10:58.233 回答