2

我想执行一个大型的数据库密集型脚本,但不需要等待该过程完成。我只想调用脚本,让它在后台运行,然后重定向到另一个页面。

编辑:我在 Windows 7 上的本地 Zend 社区服务器上工作。我可以访问项目所在的远程 linux 服务器,所以我可以在 linux 或 windows 上执行此操作。

我有这个

public function createInstanceAction()
{
    //calls a seperate php process which creates the instance
    exec('php -f /path/to/file/createInstance.php');


    Mage::getSingleton('adminhtml/session')->addSuccess(Mage::helper('adminhtml')->__('Instance creation process started. This may take up to a few minutes.'));
    $this->_redirect('instances/adminhtml_instances/');
    return;
}

这完美地工作,但magento应用程序挂起该过程完成。它完成了我所期望的一切,不时记录到文件中,并且对它的运行方式感到满意。现在我想做的就是启动这个脚本,控制器动作不会挂起,而是重定向,就是这样。根据我对 exec() 的了解,您可以通过将我在上面调用 exec() 的方式更改为:

exec('php -f /path/to/file/createInstance.php > /dev/null 2>&1 &');

我从这里拿的

如果我在 exec 调用中添加 "> /dev/null 2>&1 &" ,它不会按预期等待,但它不再执行脚本。有人能告诉我为什么吗,如果是这样,请告诉我如何让它工作?

这可能是与权限相关的问题吗?

谢谢

编辑:我假设如果我使用 (/dev/null 2>&1 &) 调用 exec 函数,将任何输出记录到文件中将是一个问题,因为这会取消它。那是对的吗?

4

5 回答 5

2

在花时间完全理解我自己的问题以及可以回答的方式之后,我准备了我的解决方案。

感谢大家的建议,感谢大家在提问时原谅我的随意,毫无准备。

上述问题的答案取决于许多因素,例如您所指的操作系统、您正在运行的 php 模块,甚至您正在运行的网络服务器。所以如果我不得不再次开始这个问题,我要做的第一件事就是说明我的设置是什么。

我想在两个环境中实现这一点:

1.) Windows 7 运行 Zend 服务器社区版。2.) Linux(我的操作系统是 Linux odysseus 2.6.32-5-xen-amd64 #1 SMP Fri Sep 9 22:23:19 UTC 2011 x86_64)

为了做到这一点,我希望它在部署到 Windows 或 linux 时以任何一种方式工作,所以我使用 php 来确定操作系统是什么。

public function createInstanceAction()
{

    //determines what operating system is Being used 
    if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN')
    {
        //This is a windows server

        //call a seperate php process to run independently from the broswer action

        pclose(popen("start php /path/to/script/script.php","r"));

    }
    else
    {
        //assuming its linux, but in fact it simply means its not windows
        // to check for linux specifically use (strtoupper(substr(PHP_OS, 0, 3)) === 'LIN')
        exec('php -f /path/to/file/script.php >/dev/null 2>&1 &');
    }
    //the browser will not hang around for this process to complete, and you can contimue with whatever actions you want.

    //myscript log any out put so i can capture info as it runs
}

简而言之,一旦你理解了问题,就提出问题。有很多方法可以实现上述目标,这只是适用于我的开发和生产环境的一种解决方案。

感谢大家的帮助。

于 2012-07-17T14:07:47.073 回答
1

PHP 弹出

从文档中(这应该可以帮助您做其他事情,而该进程正在运行;不确定关闭当前的 PHP 进程是否会杀死打开的进程):

/* Add redirection so we can get stderr. */
$handle = popen('/path/to/executable 2>&1', 'r');
echo "'$handle'; " . gettype($handle) . "\n";
$read = fread($handle, 2096);
echo $read;
pclose($handle);

解决方案2: 欺骗浏览器关闭连接(假设涉及浏览器):

ob_start();
?><html><!--example html body--></html><?php
$strContents=ob_get_clean(); 

header("Connection: Close");
header("Content-encoding: none");//doesn't work without this, I don't know why:(

ignore_user_abort(true);

header("Content-type: text/html");
header("Content-Length: ".strlen($strContents));
echo $strContents;

flush();
//at this point a real browser would close the connection and finish rendering; 
//crappy http clients like some curl implementations (and not only) would wait for the server to close the connection, then finish rendering/serving results...:(

//TODO: add long running operations here, exec, or whatever you have.
于 2012-07-15T14:34:12.307 回答
1

你可以写一个包装脚本,createInstance.sh比如

#! /bin/bash

trap "" SIGHUP
php -f "$1" > logfile.txt 2>&1 &

然后从 PHP 中调用脚本:

exec('bash "/path/to/file/createInstance.sh"');

这应该最立即从脚本中分离新的 php 进程。如果这没有帮助,您可能会尝试使用 SIGABRT、SIGTERM 或 SIGINT 而不是 SIGHUP,我不知道确切发送了哪个信号。

于 2012-07-15T14:44:49.557 回答
1

我已经能够使用:

shell_exec("nohup $command  > /dev/null & echo $!")

$command例如在哪里:

php script.php --parameter 1

我注意到了一些奇怪的行为。例如,运行mysql命令行不起作用,似乎只有 php 脚本起作用。

此外,运行cd /path/to/dir && php nohup $command ...也不起作用,我必须chdir()在 PHP 脚本中运行命令才能使其工作。

于 2012-07-16T15:21:45.380 回答
0

Zend Server 中包含的 PHP 可执行文件似乎是导致尝试在后台运行脚本(使用 exec 中的 & 运算符)失败的原因。

我们使用我们的标准 PHP 可执行文件对此进行了测试,它运行良好。这与 Zend Server 附带的版本有关,尽管我们有限地尝试弄清楚发生了什么并没有发现任何问题。

于 2012-08-15T20:53:40.150 回答