执行图形和MySQL的crontab php脚本

dced5bon  于 2023-02-21  发布在  Mysql
关注(0)|答案(1)|浏览(113)

我需要帮助下一个问题,因为我不知道为什么会发生这种情况。
我有一个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
}
...
iaqfqrcu

iaqfqrcu1#

这是一个非常糟糕的PHP代码。
例如变量$to_ret$hournowint$inthour1$inthour2被定义但从未被使用,这让我怀疑代码不稳定,这只是问题之一。
代码很难读懂,并且包含不需要的转换。请记住,简单的"06:00:00" > "05:00:00"也会正确工作。
我看不出有什么明显的错误可以解释您的问题,但是像您所遇到的这样的错误通常隐藏在难以理解的代码中。
我建议完全重写。
不如这样:

function isTimeInPeriod($time, $period)
{
    [$start, $finish] = $period;
    if ($start > $finish) {
        return ($time >= $start) || ($time <= $finish);
    } else {
        return ($time >= $start) && ($time <= $finish);
    }
}

function system_is_down($downtimeCalender, $datetime, $verbose = false){
    $time      = $datetime->format("H:i:s");
    $dayofweek = $datetime->format("N");
    if (array_key_exists($dayofweek, $downtimeCalender)) {
        foreach ($downtimeCalender[$dayofweek] as $periodNo => $period) {
            if (isTimeInPeriod($time, $period)) {
                return $verbose ? [true, $dayofweek, $periodNo] : true;
            }
        }
    }
    return $verbose ? [false, -1, -1] : false;
}

我保持了代码与你的代码或多或少的兼容性,但是尽可能地简化了它。更简单的代码意味着它更容易理解,bug隐藏的地方也更少。
这段代码未经测试,所以如果你想使用它,你必须先自己测试一下。
这能解决你的问题吗?我有我的怀疑。它能,但我怀疑你的小妖精藏在别的地方。
难道没有比使用电子邮件更直接的方法来查看系统是否在线吗?

相关问题