我有5个运行PHP文件的cron作业。 PHP文件检查MySQL数据库中是否有需要处理的项目。由于cron同时启动所有脚本,似乎有些项目会被处理两次,有时甚至会被处理多达五次。
在其中一个脚本中选择文件后,它立即发送UPDATE查询,以便其他作业不再运行它。但看起来它仍然是双重处理。
如何防止其他脚本处理之前由其他cron作业选择的项目?
答案 0 :(得分:4)
此问题称为“竞争条件”。在这种情况下,它由于SELECT和UPDATE而发生,虽然一个接一个地调用,但不是单个操作。因此,有两个作业可能会选择相同的作业,然后首先执行UPDATE,然后再执行UPDATE。所以他们同时继续这项工作。
然而,有一种解决方法。 您可以在包含当前cron作业工作者ID的表中添加一个字段(如果在一台计算机上运行它,则可能是PID)。在工作人员中,您首先执行UPDATE,尝试为其预留作业:
UPDATE jobs
SET worker = $PID, status = 'processing'
WHERE worker IS NULL AND status = 'awaiting' LIMIT 1
然后验证您是否成功为此工作人员保留了一份工作:
SELECT * FROM jobs WHERE worker = $PID
如果它没有给你返回一行,则意味着其他工人首先要保留它。您可以从第1步再次尝试获取另一份工作。如果确实返回了一行,则执行所有处理,然后最后更新:
UPDATE jobs
SET status = 'done', worker = NULL
WHERE id = $JOB_ID
答案 1 :(得分:2)
我认为你使用信号量有一个典型的问题。看看这篇文章:
http://www.re-cycledair.com/php-dark-arts-semaphores
这个想法将首先出现在每个脚本中,请求相同的信号量并等待它自由。然后在执行此操作时选择并更新数据库,释放信号量并启动该过程。这是唯一可以确保只有一个脚本正在读取数据库而另一个脚本即将在其上写入的方法。
答案 2 :(得分:0)
我会重新开始。这一思路:
处理一个项目需要时间。大约30秒。如果我有五个cron作业,则在30秒内处理五个项目
这是完全错误的,你不应该记住你的代码。
通过这种逻辑,为什么不做100个cron工作并且每30秒做100个?回答,因为你的服务器不是RoadRunner而且会崩溃并失败。
你应该
修改强>
即使有了第三方服务器的新知识,我的逻辑仍然存在,不要启动你无法控制的多个电话,事实上现在这一点更为重要。
如果你不知道他们对这些电话采取了什么行动,那么你无法确定它们是否处于正确的顺序,何时处理或者处理它们。所以只需拨打一个电话就可以确保不进行双重处理。
技术解决方案是让他们改善处理时间或缓存回复 - 但这可能与您的情况无关。