来自服务器控制器的 Symfony 运行 命令

Symfony run command from controller on the server

我想清除控制器的缓存。我已将命令定义为服务并调用它。

clear_cache_command_service:
    class: Symfony\Bundle\FrameworkBundle\Command\CacheClearCommand
    calls:
       - [setContainer, ["@service_container"] ]

In my controller I have a form to choose a command, and when the cache-clearing command is chosen it 运行s:

    $clearCacheCommand = $this->container->get('clear_cache_command_service');
    $clearCacheCommand->run(new ArrayInput(array()), new ConsoleOutput());

这 运行 会持续一段时间,因为它还会预热缓存(我实际上希望它也预热缓存)。它也会超时,所以我也需要 set_time_limit 它。

有没有办法在浏览器中 return 响应并让命令 运行 在服务器上完成?我不希望客户继续等待它完成。

由于 php 的工作方式 - 同步 - 不可能以 "classic" 方式执行,您需要等到命令完成才能终止并发送响应。这里的解决方案是合并 worker 模式。您可以找到一些有用的信息 here。基本上你需要将 "clear cache" 任务添加到队列并让其他进程处理这个队列,所以在你的情况下调用 clear cache 命令。

symfony 在这种情况下使用的一个常见解决方案是使用 RabbitMQ,有很多关于它的资源:

Using in symfony

RabbitMQBundle

Let RabbitMQ Do The Work In Your Symfony2 Application

对于响应后的 运行 命令,您必须在 kernel.terminate 事件上使用侦听器。此事件的目的是在已向客户端提供响应后执行任务。

// send the headers and echo the content
$response->send();

// triggers the kernel.terminate event
$kernel->terminate($request, $response);

Listener example

The kernel.terminate Event documentation

我找到了一种方法。这将立即 return 响应并在后台运行命令 运行。不确定这是多么糟糕的做法。

/**
 * @Service("background_command_runner")
 */
class BackgroundCommandRunner
{
    private $kernelDir;


    /**
     * @InjectParams({
     *     "kernelDir" = @Inject("%kernel.root_dir%")
     * })
     */
    public function __construct($kernelDir)
    {
        $this->kernelDir = $kernelDir;
    }

    public function run($cmd)
    {
        $path = $this->kernelDir . '\console ';

        $fullCmd = "php " . $path . $cmd;

        if (substr(php_uname(), 0, 7) == "Windows") {
            pclose(popen("start /B " . $fullCmd, "r"));
        } else {
            exec($fullCmd . " >> logs/theme.log &");
        }
    }

    public function clearCache($env = "dev", $warm = true)
    {

        $toWarm = $warm ? "" : " --no-warmup";

        $cmd = "cache:clear " . "--env=" . $env . $toWarm;

        $this->run($cmd);

    }


}

作为已经提到的 RabbitMQ 的替代品,您可以查看 JMSJobBundle http://jmsyst.com/bundles/JMSJobQueueBundle/master/installation

我在此给出的一些代码示例是我对类似问题的较早回答: