George Irimiciuc
George Irimiciuc

Reputation: 4633

Symfony run command from controller on the server

I want to clear the cache from the controller. I have defined the command as a service and call it.

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 runs:

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

This however runs for a while, since it also warms up the cache (I actually want it to also warm it up). It also times out so I need to set_time_limit it, too.

Is there a way to return a response in the browser and let the command run and finish on the server? I don't want the client to keep waiting for it to finish.

Upvotes: 3

Views: 1496

Answers (4)

George Irimiciuc
George Irimiciuc

Reputation: 4633

I found a way to do it. This will immediately return a response and have the command run in background. Not sure how much of a bad practice it is.

/**
 * @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);

    }


}

Upvotes: 0

Evgeniy Kuzmin
Evgeniy Kuzmin

Reputation: 2462

As an alternative of RabbitMQ that was mentioned about already, you can take a look to JMSJobBundle http://jmsyst.com/bundles/JMSJobQueueBundle/master/installation

Some code example I gave at this my older answer to similar question: Asynchronously calling a Command in Symfony2

Upvotes: 1

Anna Adamchuk
Anna Adamchuk

Reputation: 720

For running command after response you have to use listener on kernel.terminate event. The purpose of this event is to perform tasks after the response was already served to the client.

// 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

Upvotes: 2

Tomasz Madeyski
Tomasz Madeyski

Reputation: 10890

Because of how php works - synchronously - it is not possible to do in a "classic" way in which you need to wait until command completes to terminate and send the response. Solution here is to incorporate worker pattern. You can find some useful info here. Basically you need to add "clear cache" task to queue and let other process handle this queue so in you case call clear cache command.

A common solution used in symfony in such cases is using RabbitMQ, there's a lot of resources about it:

Using in symfony

RabbitMQBundle

Let RabbitMQ Do The Work In Your Symfony2 Application

Upvotes: 4

Related Questions