短篇故事:
我有一个名为 ( cron_mailings.php
) 的脚本,我需要知道它目前是否正在运行。是否有像 $_SERVER 这样的函数或变量来获取当前脚本 ( cron_mailings.php
) 的实例数?因为我不希望脚本在任何给定时刻运行不止一次。
很长的故事:
我们有一个cron job
调用脚本列表的脚本,其中一个脚本是 ( cron_mailings.php
)。
cron_mailings.php
转到mailings
表,获取电子邮件记录列表 - 比如说前 100 个 - 然后发送并从表中删除它们。稍后cron job
将再次执行并调用cron_mailings.php
将处理接下来的 100 封电子邮件。
问题是,有人错误地设置了 cron 作业,上周它在 5 秒内运行了 6 次,我们有一个典型的竞争条件,第一个实例获取前 100 个用户,而它正在处理用户 #10 的另一个实例相同的脚本被调用cron job
,cron_mailings
运行并获取了 100 个用户。现在,这两个脚本都与 90 个两次收到同一电子邮件的用户重叠。
我们已经修复了 cron 工作,但以防万一我不得不找到解决方案,因为我不知道将来谁会使用该脚本,因此
我已经实现了两个解决方案:
将字段标志添加到
mailings
名为is_fetched
(1 表示已获取,0 否则)的 db 表中。并将 cron_mailings.php 设置为仅获取标记为 is_fetched =0 的记录。通过该解决方案,脚本的多个实例实际上可以在表的不同部分上运行和工作。例如,第一个实例调用前 100 条记录并将 1 分配给 is_fetched,另一个实例将出现并获取后 100 条记录,其中 is_fetched = 0 和在他们身上工作。通过将标志放入 db 表来阻止整个脚本以了解脚本是否正在运行,然后在脚本的顶部类似于:
check if (is_cron_maillings_running() === 'Y') { die("script is running at the moment"); } else { set_is_cron_maillings_running("Y"); // do some stuff - send emails and save the world //1 //. //. //10 set_is_cron_maillings_running("N"); }
两种解决方案都很好(基本上第二个会压倒第一个)
但我有一个问题:
如果脚本在到达最后一行之前在第 1 步和第 10 步之间死亡/崩溃/抛出错误/db 服务器消失/.etc set_is_cron_maillings_running("N");
怎么办?cron 作业调用的任何其他脚本将在 db 表中看到 is_cron_maillings_running = Y 并且永远不会再次执行,除非有人手动将值重新分配给 N。
对于寻找更好的锁定脚本方法的建议,我持开放态度。到目前为止,我认为,如果我设法从服务器本身获取正在运行的脚本列表(搜索当前脚本是否正在运行),这比将值分配给脚本无法真正完全执行的数据库表更安全并且分配正在运行= N。