我需要帮助下一个问题,因为我不知道为什么会发生这种情况。
我有一个RHEL,其中是crontab一个PHP脚本,每5分钟运行一次。
05,15,25,35,45,55 * * * * /usr/bin/php /path/to/script/MYSCRIPT.php
00,10,20,30,40,50 * * * * /usr/bin/php /path/to/script/MYSCRIPT.php
脚本:
1-收集存储在MySQL中的信息
2-通过图形API收集收件箱邮件(在O365上)
3-执行一些检查
邮件接收的概念是一种"心跳"从一个系统,所以每1小时的系统发送一封邮件,我只需要检查它是否到达。
检查(第3点)包括:如果邮件到达的时间不晚于上一封邮件之后的1个半小时,则一切正常,否则它发送类似于"系统XXX出现故障"的警报。
由于许多活动系统(发送心跳)一天一次或两次被故意禁用,我在mysql表中添加了一个downtime字段,它实际上是一个json字符串。(1星期一至7星期日)
{
"1":{"0":["06:50:00","07:10:00"]},
"2":{"0":["06:50:00","07:10:00"]},
"3":{"0":["06:50:00","07:10:00"]},
"4":{"0":["06:50:00","07:10:00"]},
"5":{"0":["06:50:00","07:10:00"]},
"6":{"0":["06:50:00","07:10:00"]},
"7":{"0":["06:50:00","07:10:00"]}
}
在代码中有一个函数检查邮件是否在停机时间范围内到达:param:停机日历,now(datetime),null(第三个参数通常为null)
function is_downtime($cal,$now,$getKey=null){
$dayofweek = $now->format("N");
$to_ret=array();
$hournowint = intval($now->format("His"));
if(array_key_exists($dayofweek, $cal)){
foreach ($cal[$dayofweek] as $key => $value) {
$inthour1 = intval(str_replace(":", "", trim($value[0])));
$inthour2 = intval(str_replace(":", "", trim($value[1])));
if(isBetween($value[0],$value[1],$now->format("H:i:s"))){
if($getKey){return [true,$dayofweek,$key];}
return true;
}
}
}
if($getKey){return [false,-1,-1];}
return false;
}
函数为Between:
function isBetween($from, $till, $input) {
$f = DateTime::createFromFormat('!H:i:s', $from);
$t = DateTime::createFromFormat('!H:i:s', $till);
$i = DateTime::createFromFormat('!H:i:s', $input);
if ($f > $t) $t->modify('+1 day');
return ($f <= $i && $i <= $t) || ($f <= $i->modify('+1 day') && $i <= $t);
}
我可以向你保证这个函数运行良好,每5分钟这个函数就会被调用一次:
...
if(is_downtime(json_decode($conf["down_calendar"],true),$dtnow)){
//do stuff
}else{
//do other stuff
}
...
但有时,当我传递一个日历和一个日期时间,显然不是我的停机时间范围,它进入无论如何一个真实的情况。
示例:
$dtnow显然是一个明确的新日期时间,日历与previously相同
$dtnow=new Datetime();
$calendar='{"1":{"0":["06:50:00","07:10:00"]},"2":{"0":["06:50:00","07:10:00"]},"3":{"0":["06:50:00","07:10:00"]},"4":{"0":["06:50:00","07:10:00"]},"5":{"0":["06:50:00","07:10:00"]},"6":{"0":["06:50:00","07:10:00"]},"7":{"0":["06:50:00","07:10:00"]}}'
如果我把这个参数传递给"isDowntime"函数,现在=星期五16:33,函数说这是真的(显然是错的).为了有证据,我添加了一些日志代码写入文件:
$log->write("DBG - conf=".json_encode($conf));
$log->write("DBG - dtnow=".$dtnow->format("YmdHis"));
if(is_downtime(json_decode($conf["down_calendar"],true),$dtnow)){
$log->write("II - CNT - configuration XX/YY is in downtime");
//do stuff
}else{
//do other stuff
}
日志显示:
17/02/23 16:35:04 : DBG - conf={ ..., "down_calendar":"{\"1\":{\"0\":[\"06:50:00\",\"07:10:00\"]},\"2\":{\"0\":[\"06:50:00\",\"07:10:00\"]},\"3\":{\"0\":[\"06:50:00\",\"07:10:00\"]},\"4\":{\"0\":[\"06:50:00\",\"07:10:00\"]},\"5\":{\"0\":[\"06:50:00\",\"07:10:00\"]},\"6\":{\"0\":[\"06:50:00\",\"07:10:00\"]},\"7\":{\"0\":[\"06:50:00\",\"07:10:00\"]}}", ...}
17/02/23 16:35:04 : DBG - dtnow=20230217163500
17/02/23 16:35:04 : II - CNT - configuration XX/YY is in downtime
事实是,如果在问题出现后用相同的参数执行函数100次,函数会正确地返回"false"。这个问题不会反复出现,比如每周五的16:35,所以调试起来比较困难。
这怎么可能呢?你能帮我,不是解决,但至少了解我如何才能更好地调试问题。
先谢谢你。
...
if(is_downtime(json_decode($conf["down_calendar"],true),$dtnow)){
//do stuff
}else{
//do other stuff
}
...
1条答案
按热度按时间iaqfqrcu1#
这是一个非常糟糕的PHP代码。
例如变量
$to_ret
,$hournowint
,$inthour1
和$inthour2
被定义但从未被使用,这让我怀疑代码不稳定,这只是问题之一。代码很难读懂,并且包含不需要的转换。请记住,简单的
"06:00:00" > "05:00:00"
也会正确工作。我看不出有什么明显的错误可以解释您的问题,但是像您所遇到的这样的错误通常隐藏在难以理解的代码中。
我建议完全重写。
不如这样:
我保持了代码与你的代码或多或少的兼容性,但是尽可能地简化了它。更简单的代码意味着它更容易理解,bug隐藏的地方也更少。
这段代码未经测试,所以如果你想使用它,你必须先自己测试一下。
这能解决你的问题吗?我有我的怀疑。它能,但我怀疑你的小妖精藏在别的地方。
难道没有比使用电子邮件更直接的方法来查看系统是否在线吗?