php - Yii Php 执行异步后台请求

标签 php asynchronous yii request background-process

您好,我正在尝试在后台执行一个LONG RUNNING 请求(操作)。

function actionRequest($id){

//execute very long process here in background but continue redirect

Yii::app()->user->setFlash('success', "Currently processing your request you may check it from time to time.");
$this->redirect(array('index', 'id'=>$id));
}

我想要实现的是不要让用户等待处理请求,因为它通常需要 5-10 分钟,而且请求通常会超时,即使我将超时设置得更长,也要等待 5-10 分钟。不是一个好的用户体验。

所以我想立即返回页面通知用户他/她的请求正在处理中,同时他/她仍然可以浏览,并在应用程序中做其他事情,然后他/她可以返回页面并查看他/她的请求已被处理。

我研究了 Yii 扩展 backjob , 它有效,重定向立即执行(不知何故是后台请求),但是当做其他事情时,比如在网站中导航,它不会加载,而且似乎请求仍然存在,我无法继续使用应用程序,直到请求完成。

类似的扩展runactions promise 同样的事情,但我什至无法让它工作,它说它“触及一个 url”,就像火灾和忘记工作但不起作用。

我还尝试研究消息队列服务,例如 Gearman , RabbitMQ ,但它确实技术含量很高,我什至无法在我的 Windows 机器上安装 Gearman,因此“农业”服务对我不起作用。后台处理的一些答案包括 CRON 和 AJAX,但这听起来不太好,而且还有很多问题。

是否有任何其他解决异步后台处理的方法?我真的为此努力寻找,我真的不是在寻找高级/复杂的解决方案,如“将工作分包给多台机器”等。非常感谢!

最佳答案

如果您希望能够通过 Yii 运行异步作业,您可能别无选择,只能尝试使用一些 AJAX 以异步检索作业的状态。以下是对我有用的高级指南。希望这会以某种方式帮助您!


设置控制台操作

要运行后台作业,您需要使用 Yii 的控制台组件。在/protected/commands 下,创建一个包含 actionRequest() 的网络 Controller 副本(例如/protected/commands/BulkCommand.php)。

这应该允许您进入/protected 文件夹并运行 yiic bulk request

请记住,如果您之前没有创建过控制台应用程序,则需要像为 Web 应用程序那样设置它的配置。将/protected/config/main.php 直接复制到/protected/config/console.php 应该可以完成 90% 的工作。


自定义运行异步控制台作业的扩展

对我有用的是结合使用两个扩展名:CConsoleTConsoleRunner . TConsoleRunner 使用 popen 运行 shell 脚本,这在 Windows 和 Ubuntu 上对我有用。我只是将其 run() 代码合并到 CConsole 中,如下所示:

public function popen($shell, $redirectOutput = '')
{
    $shell = $this->resolveCommandLine($shell, false, $redirectOutput);
    $ret = self::RETURN_CODE_SUCCESS;
    if (!$this->displayCommands) {
        ob_start();
    }

    if ($this->isWindows()) {
        pclose(popen('start /b '.$shell, 'r'));
    }
    else {
        pclose(popen($shell.' > /dev/null &', 'r'));
    }

    if (!$this->displayCommands) {
        ob_end_clean();
    }
    return $ret;
}

protected function isWindows()
{
    if(PHP_OS == 'WINNT' || PHP_OS == 'WIN32')
        return true;
    else 
        return false;
}

之后,我将 CConsole 的 runCommand() 更改为以下内容:

public function runCommand($command, $args, $async = false, &$outputLines = null, $executor = 'popen')
    {
        ...
        switch ($executor) {
            ...
            case 'popen':
                return $this->popen($shell);
            ...
        }
    }


运行异步作业

通过以上设置,您现在可以使用以下代码片段来调用我们之前创建的 yiic 批量请求

$console = new CConsole();
$console->runCommand('bulk request', array(
    '--arg1="argument"',
    '--arg2="argument"',
    '--arg3="argument"',
));

您可以将其插入到原始的 actionRequest() 中。


检查状态

很遗憾,我不确定您的批量请求在做什么工作。对于我自己,我正在收集一大堆文件并将它们放在一个文件夹中。我知道我希望输入多少文件,所以我可以轻松地创建一个 Controller 操作来验证到目前为止已经创建了多少文件,并将 % 的状态作为一个简单的除法。

关于php - Yii Php 执行异步后台请求,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26269872/

相关文章:

javascript - 如何导出由 async/await 方法返回的对象

javascript - 如何记录、创建脚本然后立即使用它

php - 从 Joomla 移除 hasTip javascript 代码

php - CSV 导出/导入 PHPExcel

php - 功能测试代理会影响所有 guard 吗?

php - 将 Yii 站点转移到新服务器

php - Yii 迁移和自定义抽象数据类型

php - 为什么稍后关闭查询 ")"?

database - Django ORM 数据库查询会阻塞服务器,还是异步的?

php - Yii 1.1.3 设置依赖下拉列表的选择值