退出时自动重启PHP脚本

Ala*_*air 18 php

有没有一种方法可以在退出时自动重启PHP脚本,无论它是否已正确退出,或由于错误或内存使用量增加而终止等等?

nic*_*kl- 49

PHP脚本也可以通过PCNTL重启.

免责声明:本练习的目的只是为了证明PHP完全能够重启自己并回答这个问题:

有没有一种方法可以在退出时自动重启PHP脚本,无论它是否已正确退出,或因错误而终止?

因此,我们可以深入了解有关unix进程的任何细节,因此我建议您从PCNTL本书开始,或参考了解更多详细信息.

在这些示例中,我们假设它是一个在*nix环境中从具有半正式shell的终端使用以下命令启动的PHP CLI脚本:

$ php i-can-restart-myself.php 0
Run Code Online (Sandbox Code Playgroud)

我们传递一个重启计数属性作为重新启动进程的指示器.

我可以自动重启PHP脚本吗?

我可以!

<?php
    echo ++$argv[1];     // count every restart
    $_ = $_SERVER['_'];  // or full path to php binary

    echo "\n======== start =========\n";
    // do a lot of stuff
    $cnt = 0;
    while( $cnt++ < 10000000 ){}
    echo "\n========== end =========\n";

    // restart myself
    pcntl_exec($_, $argv);
Run Code Online (Sandbox Code Playgroud)

无论它是否已正确终止?

是的,如果终止我可以重启!

<?php
    echo ++$argv[1];    
    $_ = $_SERVER['_']; 

    register_shutdown_function(function () {
        global $_, $argv; // note we need to reference globals inside a function
        // restart myself
        pcntl_exec($_, $argv);
    });

    echo "\n======== start =========\n";
    // do a lot of stuff
    $cnt = 0;
    while( $cnt++ < 10000000 ){}
    echo "\n========== end =========\n";

    die; // exited properly
    // we can't reach here 
    pcntl_exec($_, $argv);
Run Code Online (Sandbox Code Playgroud)

或因错误而终止?

同上!

<?php
    echo ++$argv[1];    
    $_ = $_SERVER['_']; 

    register_shutdown_function(function () {
        global $_, $argv; 
        // restart myself
        pcntl_exec($_, $argv);
    });

    echo "\n======== start =========\n";
    // do a lot of stuff
    $cnt = 0;
    while( $cnt++ < 10000000 ){}
    echo "\n===== what if? =========\n";
    require 'OOPS! I dont exist.'; // FATAL Error:

    // we can't reach here
    echo "\n========== end =========\n";        
    die; // exited properly
    // we can't reach here 
    pcntl_exec($_, $argv);
Run Code Online (Sandbox Code Playgroud)

但是你知道我想要的不仅仅是这个吗?

当然!我可以重启kill,hub甚至Ctrl-C!

<?php
    echo ++$argv[1];     
    $_ = $_SERVER['_'];  
    $restartMyself = function () {
        global $_, $argv; 
        pcntl_exec($_, $argv);
    };
    register_shutdown_function($restartMyself);
    pcntl_signal(SIGTERM, $restartMyself); // kill
    pcntl_signal(SIGHUP,  $restartMyself); // kill -s HUP or kill -1
    pcntl_signal(SIGINT,  $restartMyself); // Ctrl-C

    echo "\n======== start =========\n";
    // do a lot of stuff
    $cnt = 0;
    while( $cnt++ < 10000000 ){}
    echo "\n===== what if? =========\n";
    require 'OOPS! I dont exist.'; // FATAL Error:

    // we can't reach here
    echo "\n========== end =========\n";        
    die; // exited properly
    // we can't reach here 
    pcntl_exec($_, $argv);
Run Code Online (Sandbox Code Playgroud)

我现在如何终止它?

如果通过按住Ctrl-C来填充进程,您可能只是在关闭的某个地方捕获它.

我不想看到所有这些错误,我也可以重新开始吗?

没问题我也可以处理错误!

<?php
    echo ++$argv[1];     
    $_ = $_SERVER['_'];  
    $restartMyself = function () {
        global $_, $argv; 
        pcntl_exec($_, $argv);
    };
    register_shutdown_function($restartMyself);
    pcntl_signal(SIGTERM, $restartMyself);   
    pcntl_signal(SIGHUP,  $restartMyself);   
    pcntl_signal(SIGINT,  $restartMyself);   
    set_error_handler($restartMyself , E_ALL); // Catch all errors

    echo "\n======== start =========\n";
    // do a lot of stuff
    $cnt = 0;
    while( $cnt++ < 10000000 ){}

    echo $CAREFUL_NOW; // NOTICE: will also be caught

    // we would normally still go here
    echo "\n===== what if? =========\n";
    require 'OOPS! I dont exist.'; // FATAL Error:

    // we can't reach here
    echo "\n========== end =========\n";        
    die; // exited properly
    // we can't reach here 
    pcntl_exec($_, $argv);
Run Code Online (Sandbox Code Playgroud)

虽然乍一看似乎工作正常,但因为pcntl_exec在同一个进程中运行,所以我们没有注意到事情是非常错误的.如果你想生成一个新进程并让旧进程死掉,这是一个非常可行的替代方案,请参阅下一篇文章,你会发现每次迭代都会启动2个进程,因为我们会因为共同的疏忽而触发PHP注意和错误.当然,通过在错误处理程序中调用pcntl_exec之后确保我们die()或exit()可以很容易地纠正这一点,否则PHP假定容差已被接受并继续.

我想说的是,即使您能够重新启动失败的脚本,这也不是允许破坏代码的借口.虽然这种做法可能存在可行的用例,但我强烈反对应该采用失败重启作为脚本因错误而失败的解决方案!正如我们从这些例子中看到的那样,没有办法确切地知道它失败了,所以我们无法确定它将从何处开始.寻求可能看起来工作正常的"快速修复"解决方案现在可能会遇到更多问题.

我宁愿看到通过一些适当的单元测试来解决缺陷,这将有助于清除罪魁祸首,以便我们可以纠正问题.如果PHP内存不足,可以通过在使用后取消设置变量来保守使用资源来避免.(顺便说一句,你会发现分配null比使用unset对同样的结果快得多)我担心,如果没有解决,重启肯定会成为你已经拥有的蠕虫的合适开启者.


nic*_*kl- 8

这里是龙.

高级用法,而不是胆小的人.

要启动单独的进程,请将restartMyself函数更改为:

<?php
    $restartMyself = function () {
        global $_, $argv; 
        if(!pcntl_fork()) // We only care about the child fork
            pcntl_exec($_, $argv);
        die; // insist that we don't tolerate errors  
    }
Run Code Online (Sandbox Code Playgroud)

这肯定是一次冒险,如果你设法在进程中捕获它们,那么追逐可以重新开始杀戮的进程.=)

确保脚本有足够的时间来执行此操作,您可能有足够的时间来终止它.

尝试:

$ kill -9
Run Code Online (Sandbox Code Playgroud)

要么:

$ kill -s KILL
Run Code Online (Sandbox Code Playgroud)

坚持不死生物死了.这不是空闲参考,因为你最好考虑僵尸和孤儿,但最终即使是最棘手的进程通常仍然需要一个父级,所以杀死shell会话应该让他们休息.

所有标准免责声明适用,祝你好运!=)


Zuu*_*uul 5

假设:

  • 调用相同的脚本文件x次
  • 如果它被中断/结束/停止则重新呼叫
  • 无限循环的自动化过程

为实现您的目标[Unix/Linux解决方案],我们会想到一些选项:

  1. 使用BASH脚本,以便可以恢复停止/结束/中断后的PHP脚本:

    #!/bin/bash
    clear
    date
    
    php -f my_php_file.php
    sleep 100
    # rerun myself
    exec $0
    
    Run Code Online (Sandbox Code Playgroud)
  2. 胖控制器执行处理程序,这是您正在寻找的关键功能:

    • 用于重复运行其他程序
    • 可以并行运行任何脚本/程序的许多实例
    • 任何脚本在完成执行后都可以重新运行

    与CRON非常相似,但这些关键功能正是您所需要的

  3. 使用CRON,你可以让它以例如一分钟的间隔调用你的PHP脚本,然后在PHP脚本的开始使用这段代码,你将能够控制运行的线程数,如果8已经存在则退出运行:

    exec('ps -A | grep ' . escapeshellarg(basename(__FILE__)) , $results);
    if (count($results) > 7) {
      echo "8 Already Running\n"
      die(0);
    }
    
    Run Code Online (Sandbox Code Playgroud)

    搜索使用当前文件的相同路径运行的进程,并返回找到的进程数.然后,如果他们更大7,退出.