【问题标题】:crontab php script that execute graph and mysql执行图形和 mysql 的 crontab php 脚本
【发布时间】:2023-02-20 20:01:00
【问题描述】:

我需要以下问题的帮助,因为我无法弄清楚为什么会这样。
我有一个 RHEL,其中 crontab 是一个每 5 分钟运行一次的 PHP 脚本。

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-通过graph api,收集收件箱邮件(在O365上)
3-执行一些检查

邮件接收的概念是来自系统的一种“心跳”,所以系统每 1 小时发送一封邮件,我只需要检查它是否到达。
检查(第 3 点)包括:如果邮件在上一封电子邮件后的 1.5 小时内到达,则一切正常,否则它会发送类似“系统 XXX 似乎已关闭”的警报。
由于许多活跃的系统(发送心跳)一天一次或两次被故意禁用,我在 mysql 表中添加了一个停机时间字段,它实际上是一个 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;
}

函数是介于:

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
}
...

但有时,当我传递一个日历和一个显然不是停机时间范围的日期时间时,它无论如何都会进入一个真实的案例。
例子:

$snow 显然是一个明确的新日期时间,日历和以前一样

$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”函数并且 now = friday 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
}
...

【问题讨论】:

  • 无关fyi:*/5 * * * *每5分钟检查一次
  • 我知道......但我更喜欢这种方式,不仅对我来说,因为有时其他用户会阅读 crontab :D

标签: php mysql json logging graph


【解决方案1】:

这是写得非常糟糕的 PHP 代码。

例如,变量$to_ret$hournowint$inthour1$inthour2 已定义但从未使用过。这让我怀疑代码不稳定。这只是问题之一。

代码难以阅读并且包含不需要的转换。请记住,一个简单的"06:00:00" &gt; "05:00:00" 也可以正常工作。

我没有看到任何可以解释您的问题的明显错误,但是像您遇到的错误一样,错误通常隐藏在难以理解的代码中。

我建议完全重写。

怎么样:

function isTimeInPeriod($time, $period)
{
    $start = $period[0];
    $finish = $period[1];
    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 隐藏的地方也更少。

此代码未经测试,因此如果您想使用它,您必须先自己进行测试。

这能解决您的问题吗?我有我的疑问。可以,但我怀疑你的 gremlin 藏在别处。

有没有比使用电子邮件更直接的查看系统是否在线的方法?

【讨论】:

    猜你喜欢
    • 2016-03-02
    • 2014-05-03
    • 2013-08-30
    • 1970-01-01
    • 2011-11-15
    • 1970-01-01
    • 2020-03-16
    • 2013-04-19
    • 2020-05-30
    相关资源
    最近更新 更多