长PHP脚本运行多次

Han*_*ink 4 php cron

我有一个产品数据库,可以在早上与产品数据同步.

这个过程非常清楚:

  • 通过查询从数据库中获取所有产品
  • 遍历所有产品,并通过product_id从其他服务器获取和xml
  • 从xml更新数据
  • 将更改记录到文件.

如果我查询少量的项目,但将其限制为500个随机产品,一切都很顺利.但是当我查询所有产品时,我的脚本SOMETIMES继续使用fritz并开始多次循环.几个小时后,我仍然看到我的日志文件在增长,产品正在增加.

我查看了我能想到的一切,例如:

  • 变量是否未使用两次而没有相互覆盖
  • 该函数是否自行调用
  • 是否会出现少量产品:没有.
  • 使用cronjob调用脚本,设置正常.(是)

使其特别奇怪的原因是它有时是正确的,有时它不会.这可能是一些记忆问题吗?

编辑 wget -q -O /dev/null http://example.eu/xxxxx/cron.php?operation=sync它在webmin中调用特定的小时和分钟

代码长达数百行......

谢谢

sat*_*n77 6

你有:

  • max_execution_time已禁用.只要需要,您的脚本将不会在该过程完成之前结束.
  • memory_limit已禁用.内存中存储的数据量没有限制.

完成500条记录没有问题.这表明脚本在下一次cronjob迭代之前完成其过程.例如,如果您的cron每小时运行一次,则会在不到一小时的时间内处理500条记录.

如果您有一个将要处理大量记录的cronjob,那么请考虑向该进程添加锁定机制.仅允许脚本运行一次,并在上一个过程完成时重新启动.

在执行php脚本之前,您可以将脚本锁创建为shell脚本的一部分.或者,如果您无法访问服务器,则可以在php脚本中使用数据库锁定,如下所示.

class ProductCronJob
{
    protected $lockValue;

    public function run()
    {
        // Obtain a lock
        if ($this->obtainLock()) {
            // Run your script if you have valid lock
            $this->syncProducts();

            // Release the lock on complete
            $this->releaseLock();
        }
    }

    protected function syncProducts()
    {
        // your long running script
    }

    protected function obtainLock()
    {
        $time = new \DateTime;
        $timestamp = $time->getTimestamp();
        $this->lockValue = $timestamp . '_syncProducts';

        $db = JFactory::getDbo();

        $lock = [
            'lock'         => $this->lockValue,
            'timemodified' => $timestamp
        ];
        // lock = '0' indicate that the cronjob is not active.
        // Update #__cronlock set lock = '', timemodified = '' where name = 'syncProducts' and lock = '0'
//        $result = $db->updateObject('#__cronlock', $lock, 'id');

//        $lock = SELECT * FROM #__cronlock where name = 'syncProducts';

        if ($lock !== false && (string)$lock !== (string)$this->lockValue) {
            // Currently there is an active process - can't start a new one

            return false;

            // You can return false as above or add extra logic as below

            // Check the current lock age - how long its been running for
//            $diff = $timestamp - $lock['timemodified'];
//            if ($diff >= 25200) {
//                // The current script is active for 7 hours.
//                // You can change 25200 to any number of seconds you want.
//                // Here you can send notification email to site administrator.
//                // ...
//            }
        }

        return true;
    }

    protected function releaseLock()
    {
        // Update #__cronlock set lock = '0' where name = 'syncProducts'
    }
}
Run Code Online (Sandbox Code Playgroud)


ROu*_*ofF 6

你的脚本运行了相当长的时间(约45米)并且因为你没有返回任何数据而认为它是"超时".默认情况下,wget将具有900s的超时值和20的重试次数.因此,首先您应该更改wget命令以防止这种情况:

wget --tries = 0 --timeout = 0 -q -O/dev/null http://example.eu/xxxxx/cron.php?operation=sync

现在删除超时可能会导致其他问题,因此您可以发送(并刷新以强制Web服务器发送它)来自脚本的数据,以确保wget不认为脚本"超时",每1000个循环或某事像那样.把它想象成一个进度条......

请记住,当运行时间接近您的时间段时,您将遇到问题,因为2个crons将并行运行.你应该优化你的过程和/或有锁机制吗?


Han*_*ink 4

我自己解决了这个问题。感谢所有的答复!

我的 MySQL 超时,这就是问题所在。我一添加:

    ini_set('mysql.connect_timeout', 14400);
    ini_set('default_socket_timeout', 14400);
Run Code Online (Sandbox Code Playgroud)

对于我的脚本,问题停止了。我真的希望这对某人有帮助。我会投票支持所有锁定答案,因为这些答案非常有帮助!