2012-10-29 33 views
6

有一个问题,我的一个团队成员正在使用PHP进行排队过程。 PHP脚本在命令行上运行,并在每个周期后递归调用自己,以检查数据库中是否有任何项目正在等待处理。如果存在,则自行分叉,处理队列中的项目并重复。如果什么都没有,它就会死亡,并且一个cron作业每5分钟就会重新启动队列。PHP队列问题 - 冗余进程

偶尔会有两个进程同时运行,抓取相同的队列,并相互进入。我正考虑在唤醒过程中引入抖动,以便在启动过程之间有一段随机的时间。

有没有更好的方法?

回答

4

抖动只是使得碰撞难以预测。

在磁盘上放置一个互斥锁。检查它是否比两个周期前更早。如果是,请忽略并删除它;它由于坠毁事件而落后了。否则,有一个已经运行,所以保释。

2

如果您的队列中的项目不必执行,您可以做这样的事情,只是让两个进程并行运行。

选择从队列中下一个作业(显然语法将取决于数据库)

LOCK TABLE queue; 

SELECT * FROM queue WHERE status <> 'INPROGRESS' ORDER BY id LIMIT 1 

UPDATE queue SET status = 'INPROGRESS' WHERE id = ? 

UNLOCK TABLES; 

做的工作,然后标记任务已完成或如果你想找到被困在地狱的工作从队列

删除,你可以存储一个作业开始的时间戳,并把它放回队列,如果它在那里多于x分钟

0

LOCK TABLE queue;是有点矫枉过正,因为它看起来是整个表,所以根本没有并发。如果使用现场更新方法,则根本不需要锁定(状态更新为INPROGRESS)。 SQL更新操作在内部执行锁定,所以像这样的事情必须同时工作:

UPDATE queue SET consumer_id='a_consumer_unique_id' status='INPROGRESS' LIMIT 1 

SELECT * FROM queue WHERE consumer_id='a_consumer_unique_id' LIMIT 1 

但是这种方法有副作用。我们必须更改标志INPROGRESS或设置consumer_id。如果消费者偷看消息(consumer_id设置为它)并且消失了消息会发生什么?它会长时间呆在队列中,所以你需要一种清理脚本来处理这些情况。

我们可以做的是将消息标记为我们的,加载到内存并从队列中删除它。只有在完成之后,我们才会开始处理它。这是如何enqueue/dbal做到这一点。

如果您需要重新交付担保,请使用像RabbitMQ这样的真正经纪商。