情况:我创建了一个cron作业。它是将客户输入的订单添加到API中。我把它设置为每一分钟运行一次。
问题:有时,当有太多待处理的订单时,在第一个订单结束之前,第二个cron作业就被调用了。这导致通过API发送重复订单。
解决方案:我在数据库中创建了一个名为cron_jobs的表。它有两列,ID和状态。运行cron作业时,它会检查状态是否为0。如果状态为0,则会将状态更新为1。它完成其过程,并将状态再次标记为0。如果作业的状态为1(意味着它已经在运行),并且再次命中,则操作将终止。
意外问题:这个解决方案在逻辑上似乎是正确的。但当我实施它时,结果令人震惊。作业运行时,其状态会更新。但当再次调用时,数据库仍然返回状态0,并继续执行。我还使用了睡眠法,这样我就有足够的时间来调查这个问题。但是数据库总是返回不正确的值,这比我使用phpmyadmin看到的值要多。
请不要认为我可能犯了一些愚蠢的错误在第一个实例被完全调用之前,文件的第二个实例总是获取不正确的值看看我的代码:
<?php
$Output = mysql_fetch_assoc(mysql_query("select status from jobs where ID='1'"));
if($Output['status'] == '0')
{
mysql_fetch_assoc(mysql_query("update jobs set status='1' where ID = '1'"));
mysql_fetch_assoc(mysql_query("update jobs set invoked = invoked+1 where ID = '1'"));
echo 'Executed';
}
else
{
echo 'Error: Another cron job already in process. Operation terminated!';
die();
}
/*I perform some lengthy tasks here*/
/*Sleep function called to check whether another instance of the program works while this one is in progress */
sleep(60);
/*Task is complete. We are marking 0 as status so that another instance is allowed to work on.*/
mysql_fetch_assoc(mysql_query("update jobs set status='0' where ID = '1'"));
?>
观察1:如果我在另一个浏览器或另一台计算机中运行第二个实例,它会完美工作。
观察2:我试图调查它是否真的被调用了好几次。我在表中做了另一列为"No_Of_Times_Invoked"。当我从同一个浏览器使用时,我发现代码实际上失败了。
SELECT
查询使用表cron_jobs
。每隔一个查询使用jobs
。我认为您的SELECT
查询失败,导致mysql_query()
返回false
。
$Output = mysql_fetch_assoc(mysql_query("select status from cron_jobs where ID='1'"));
因为这里mysql_query()
返回false
,所以mysql_fetch_assoc()
也返回false
。
if($Output['status'] == '0')
CCD_ 11是CCD_。在PHP中,当使用==
时,可以进行类型转换。在这种情况下,$Output['status'] == '0'
的求值结果为true
。(注意,$Output['status']
是null
,但null == '0'
评估为false
。类型杂耍和松散比较的乐趣。)
用替换您的查询
SELECT `status` FROM jobs WHERE ID = '1'
它应该运行正常。
我建议在mysql_*()
函数的返回值中添加更多的错误检查(使用$returnValue === false
),或者更好地切换到PDO。
在评论中讨论后更新
问题似乎是你在浏览器上进行测试。至少Firefox 23.0.1(我用来测试)在第一个请求完成之前不会发送第二个请求。这可以解释你所看到的所有行为。新的浏览器或计算机将无法重新使用连接,因此在这种情况下它可以工作。
如果我从命令行启动脚本两次(间隔五秒),它就会正常工作:第二次运行会输出Error: Another cron job already in process. Operation terminated!
。
注意,PHP确实抱怨每个mysql_query("update ...")
函数调用的mysql_fetch_assoc()
无效:
警告:mysql_fetch_assoc()要求参数1为resource,在第7行的/test/test.php中给出布尔值