1

What I want to do is to run a Symfony command separately from current request.

Goal: Generate a thumbnail from a PDF

Issue: I don't want to wait for the generation to be finished before sending response to the user.

    public function __invoke($myparam)
    {
        $command = sprintf(
            'php %s/bin/console ps:media:generate-thumbnail %s %s &',
            $this->kernel->getProjectDir(),
            'destinationPath',
            'sourcePath'
        );

        exec($command);
    }

Issue is, server still wait for the command to be done before sending response

JessGabriel
  • 1,062
  • 9
  • 18
  • Send the request via AJAX or maybe use a Cron Job? – hawkyhawk14 Sep 10 '19 at 07:06
  • 3
    The best way to do that is a queue manager. You can take a look at https://outweb.eu/symfony-messenger-et-rabbitmq/. – Arnaud Sep 10 '19 at 07:26
  • 1
    If you want it to be done asynchronously, do it actually like that. This way you're trying right now, you have very limited capabilities of handling errors in case anything goes wrong. Just as Arnaud said - use a queue and handle it in background. – Jakub Matczak Sep 10 '19 at 07:56
  • You can even roll your own "queue" with a bit of elbow grease and some flat files. But if both process need to be decoupled, really do decouple them. Starting the process from within the request is a bad idea. – yivi Sep 10 '19 at 09:32
  • I was thinking about creating a worker for this. But, this is not a so big task then I don't want to overkill everything. As there are already many worker running in the project – JessGabriel Sep 10 '19 at 09:40
  • Possible duplicate https://stackoverflow.com/questions/37733820/running-a-background-task-using-symfony-process-without-having-to-wait-for-the-p ? – Manzolo Sep 10 '19 at 17:48

3 Answers3

2

so, exec function waiting for stdio stream, so you just need to reassign it somewhere else, /dev/null is cool ^_^

public function __invoke($myparam)
    {
        $command = sprintf(
            'php %s/bin/console ps:media:generate-thumbnail %s %s > /dev/null &',
            $this->kernel->getProjectDir(),
            'destinationPath',
            'sourcePath'
        );

        exec($command);
    }
myxaxa
  • 1,391
  • 1
  • 8
  • 7
  • this might have some weird side effects, tbh. for example, if that command is long running and your current process exits/aborts/is killed, the child process may be killed as well (which may or may not be what you want). nohup may be an option. I'm with the question commenters on this, you should do this in a job that's just running and doesn't mind being blocked. – Jakumi Sep 10 '19 at 08:15
1

If you are using PHP FPM, a nice way to handle such requirements on Symfony is to use a listener on the kernel.terminate event. From the documentation:

This event is dispatched after the response has been sent (after the execution of the handle() method). It's useful to perform slow or complex tasks that don't need to be completed to send the response (e.g. sending emails).

Apart from writing a listener, you also have to add the snippet bellow to your front controller, after the $response->send() call

$response->send(); 
$kernel->terminate($request, $response);

You can find more on the symfony documentation

https://symfony.com/doc/current/components/http_kernel.html#component-http-kernel-kernel-terminate

Dimitris
  • 433
  • 3
  • 13
1

You could use Cocur Background Progress library to manage background progresses

$command = sprintf(
     'exec php %s/bin/console ps:media:generate-thumbnail %s %s &',
     $this->kernel->getProjectDir(),
     'destinationPath',
     'sourcePath'
);

$process = new BackgroundProcess($command);

$process->run();

murtho
  • 991
  • 1
  • 17
  • 38