Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Process] Process doesn't start if calling script terminates to quickly #7237

Closed
jeffreymb opened this issue Mar 1, 2013 · 18 comments
Closed
Labels

Comments

@jeffreymb
Copy link
Contributor

I am attempting to use the Process component to spaw a second (long running) process. I use ProcessBuilder to create the process, then call $process->start(). The process will only actually execute if I make my calling script sleep(1). If it terminates immediately, the new process will not execute.

Is there a way to solve this?

@pborreli
Copy link
Contributor

pborreli commented Mar 1, 2013

You should check this article

Instead of using run() to execute a process, you can start() it: run() is blocking and waits for the process to finish, start() creates a background process. One way to get feedback from a running command is to pass a callback when starting/running the process

Did you try to setup a callback ? like it's shown in the example ?

@jeffreymb
Copy link
Contributor Author

@pborreli I've read that article as well as most of the code for the Process class. As I said in my issue above, I am using the start() method, not run().

@pborreli
Copy link
Contributor

pborreli commented Mar 1, 2013

@iCode4food are you trying to launch a zombie process ? (and you didn't answered my question, are you using a callback to get feedback)

@jeffreymb
Copy link
Contributor Author

I'm developing and deploying on Windows. To add a few more details... I have a long running process that the user will initiate from the website. Instead of having the request wait for several minutes, I want a second process to actually do the work, and the client will ping the server to see if it is done and get status updates. The second, long running process that I'm executing is a Symfony CLI command.

@pborreli
Copy link
Contributor

pborreli commented Mar 1, 2013

using a sleep is not bad then, I would do :

$p->start();
while ($p->isRunning()) {
    // running
    usleep(10000);
}
// done

@jeffreymb
Copy link
Contributor Author

@pborreli That is exactly what I'm wanting to avoid. I don't want the clien'ts request to wait until the command is done executing, I want it to terminate, send it's output to the client and then ping the server until the long running command is done.

@pborreli
Copy link
Contributor

pborreli commented Mar 1, 2013

have you seen #5759 and #5476 ? I guess getting the PID of the process could help you to retrieve it afterwards, PR are closed in favor of a not-yet existent ProcessChain (afaik)

@jeffreymb
Copy link
Contributor Author

Apparently I'm not communicating my issue clearly. All that I need to do is allow the child process to continue executing after the parent request is completed. It seems that the parent request ends before the new child process is actually started and thus never starts. If I add sleep(1) after start(), all is well and fine, the child process will spin up and go to work, but I don't like the idea of having to sleep(1) just to wait for the new process to get rolling before the parent request can complete.

@romainneutron
Copy link
Contributor

I think I understand what you're doing @iCode4food ; You're trying to send an HTTP response and run a process while the response has been sent. Actually, this is not recommended to run a process through an URI, it will lead you to some security flaw. It is recommended to use a message queue such as RabbitMQ and some workers to get the job done.

If you realy want to implement your design, you have to be sure that you're working with PHP fpm wich provides fastcgi_finish_request (see http://php.net/manual/en/install.fpm.php) AND run your process on KernelEvents::TERMINATE. Implementing this should work out of the box without any need for sleep or anything

@ewebcorporation
Copy link

I have the same problem with Process component.
i use the process component to do some tasks for database management, and i've made some symfony command.

The only way i found to do in real background is with nohup (but only on linux):

   $processtorun = new Process('nohup php ../app/console sw:execute &');
    $processtorun->start();

using symfony command can prevent a little bit for error, but not for infinite loop, and be sure you doesn't have max_execution_time in php.ini (nomally disabled by default for cli).
Put manually max_execution_time in your script.
this solution is not as good as @romainneutron wrote, but it's work

@kentpachi
Copy link

thank you very much

i managed it to get it works but there's nothing to do with "no hup" in my case.

the "../app/console" triggered the process while "app/console" did not.

so thanks !

@miniyarov
Copy link
Contributor

@iCode4food I guess you might still be interested for the answer as the problem continues to exist in Process component. I resolved the issue by making a little change in Process class. change updateStatus(false) to updateStatus(true) in start method (https://github.com/symfony/symfony/blob/2.5/src/Symfony/Component/Process/Process.php#L301). stream_select will wait for the process to start, thus launching your command.

@romainneutron
Copy link
Contributor

Hello @miniyarov ,

The solution you provide is wrong: If you do this change and run the test suite, you'll see that tests would fail. Process::start should be non-blocking.

It seems you expect a blocking Process (a process that does not stop if PHP stops). In this case, you have to use Process:run or a polling loop like:

$process->start();
while ($process->isRunning()) {
    // do things here
    usleep(50000);
}

@jpilldev
Copy link

Hi.

Did you solve this problem?

I have now the same behavior, i can run a command with run method, but with start method i got an error:

*dots in command are not in real command is just to avoid all parameters here

local.ERROR: The command "ffmpeg -re -i "video1.mp4"  -acodec libmp3lame..." failed.

Exit Code: ()

Working directory: /root

Output:
================


Error Output:
================
 {"exception":"[object] (Symfony\\Component\\Process\\Exception\\ProcessFailedException(code: 0): The command \"ffmpeg -re -i "video1.mp4"  -acodec libmp3lame..." failed.

Exit Code: ()

With run function the command executes fine, so, i don't know what to do.

I need the process to run asynchronously because it could be many of them and each can take around 5 mins.

@stof
Copy link
Member

stof commented May 11, 2018

@jpilldev PHP will kill the subprocess when the main process dies. So even if you start the subprocess asynchronously to be able to keep using the main process while it runs, you should still ensure that your main process does not die before its child process.

@ttk
Copy link

ttk commented Feb 7, 2020

When using Symfony's Process class in a cli environment, it is possible to keep the process running even after the main script ends. To do this, implement your own class and overload the __destruct() method to prevent the default behaviour that stops the process by sending a SIGTERM signal.

class PersistentProcess extends Process {
  public function __destruct() {}
}

IMO, I think the Process class should allow the option to not send SIGTERM when the Process object is destroyed.

@gsouf
Copy link

gsouf commented Feb 20, 2020

@ttk very good point.

I think the behavior of symfony/process 2 was to keep things running. As of symfony 3 it's closing when script terminates

@max4ever
Copy link

When using Symfony's Process class in a cli environment, it is possible to keep the process running even after the main script ends. To do this, implement your own class and overload the __destruct() method to prevent the default behaviour that stops the process by sending a SIGTERM signal.

class PersistentProcess extends Process {
  public function __destruct() {}
}

IMO, I think the Process class should allow the option to not send SIGTERM when the Process object is destroyed.

Also adding sleep(1) helped for some reason

        $process = new PersistentProcess($cmd);
        $process->start();

        sleep(1);//give it some time to start

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests