有一个问题,我的一个团队成员正在使用PHP进行排队过程。 PHP脚本在命令行上运行,并在每个周期后递归调用自己,以检查数据库中是否有任何项目正在等待处理。如果存在,则自行分叉,处理队列中的项目并重复。如果什么都没有,它就会死亡,并且一个cron作业每5分钟就会重新启动队列。PHP队列问题 - 冗余进程
偶尔会有两个进程同时运行,抓取相同的队列,并相互进入。我正考虑在唤醒过程中引入抖动,以便在启动过程之间有一段随机的时间。
有没有更好的方法?
有一个问题,我的一个团队成员正在使用PHP进行排队过程。 PHP脚本在命令行上运行,并在每个周期后递归调用自己,以检查数据库中是否有任何项目正在等待处理。如果存在,则自行分叉,处理队列中的项目并重复。如果什么都没有,它就会死亡,并且一个cron作业每5分钟就会重新启动队列。PHP队列问题 - 冗余进程
偶尔会有两个进程同时运行,抓取相同的队列,并相互进入。我正考虑在唤醒过程中引入抖动,以便在启动过程之间有一段随机的时间。
有没有更好的方法?
抖动只是使得碰撞难以预测。
在磁盘上放置一个互斥锁。检查它是否比两个周期前更早。如果是,请忽略并删除它;它由于坠毁事件而落后了。否则,有一个已经运行,所以保释。
如果您的队列中的项目不必执行,您可以做这样的事情,只是让两个进程并行运行。
选择从队列中下一个作业(显然语法将取决于数据库)
LOCK TABLE queue;
SELECT * FROM queue WHERE status <> 'INPROGRESS' ORDER BY id LIMIT 1
UPDATE queue SET status = 'INPROGRESS' WHERE id = ?
UNLOCK TABLES;
做的工作,然后标记任务已完成或如果你想找到被困在地狱的工作从队列
删除,你可以存储一个作业开始的时间戳,并把它放回队列,如果它在那里多于x分钟
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这样的真正经纪商。