Skip to content

[RFC] Process and chained commands in symfony 2.2 #5759

Closed
@romainneutron

Description

@romainneutron

Hello,

I wanted to implement signal and getPid methods for 2.2 (see #5476).

  • Posix signal are very interesting in case of timeout ; when you ask your process to stop, you could specify a timeout when a SIGKILL could be sent. (And I'm sure you got lots of ideas to use them other ways)
  • Pid can be useful for interactions with other programs.

The Story :

There are two functions to implement these methods : proc_get_status and proc_terminate.
Actually, these methods might not work as expected inside the Process component because PHP might not run the command directly, but wraps it with sh (described in #5030).

Reminder

Chained commands

The Process component can handle such command :

new Process('git branch -a && git fetch upstream');

Inside Process, it can be summarized as :

$descriptorspec = array(array("pipe", "r"), array("pipe", "w"), array("pipe", "a"));
$process = proc_open('git branch -a && git fetch upstream', $descriptorspec, $pipes);

The sh wrapper

Let's run a command and let's ask for the Pid

$descriptorspec = array(array("pipe", "r"), array("pipe", "w"), array("pipe", "a"));
$process = proc_open('sleep 3', $descriptorspec, $pipes);
$status = proc_get_status($process);
echo $status['pid'];

will result in :

15888

That can be monitored :

grosroro 15886  1.0  0.0 254140 16164 pts/0    S+   23:19   0:00  | \_ php proc.php     
grosroro 15888  0.0  0.0   3940   580 pts/0    S+   23:19   0:00  |     \_ sh -c sleep 3
grosroro 15889  0.0  0.0   6748   568 pts/0    S+   23:19   0:00  |         \_ sleep 3

The actual Pid is 15889, not 15888 ; The status returned by proc_get_status is not the one we expected (the status of our command), but the one of the sh wrapper.
It is the same behavior with proc_terminate ; the signal is sent to the sh wrapper instead of the command.

The problem

This leads us to two conclusions :

  • All the methods that returns results or use results probed by proc_get_status might be wrong (hasBeenSignaled, getTermSignal, hasBeenStopped, getStopSignal, stop).
  • We can not currently easily signal a process or retrieve the pid in the current design.

The solution

The only solution found is to prepend the command with [exec](https://en.wikipedia.org/wiki/Exec_(operating_system\)) :

$descriptorspec = array(array("pipe", "r"), array("pipe", "w"), array("pipe", "a"));
$process = proc_open('exec sleep 3', $descriptorspec, $pipes);
$status = proc_get_status($process);
echo $status['pid'];

will result in :

9441

That can be monitored :

grosroro  9440  1.0  0.0 254140 16188 pts/0    S+   23:48   0:00  |   \_ php proc.php
grosroro  9441  0.0  0.0   6748   564 pts/0    S+   23:48   0:00  |       \_ sleep 3

proc_terminate and proc_get_status works as expected in this case.

Backward Compatibility

This solution is quite nice, but it leads to another issue :

This was working well :

$descriptorspec = array(array("pipe", "r"), array("pipe", "w"), array("pipe", "a"));
$process = proc_open('echo "hello" && echo "world"', $descriptorspec, $pipes);
// echoes "hello\nworld";
echo fgets($pipes[1], 4096);

This is not working as expected :

$descriptorspec = array(array("pipe", "r"), array("pipe", "w"), array("pipe", "a"));
$process = proc_open('exec echo "hello" && echo "world"', $descriptorspec, $pipes);
// echoes "hello";
echo fgets($pipes[1], 4096);

Proposals

Parse command line and allow pid/signal access to non-chained commands

this would prepend command line with "exec" only for atomic commands.

  • pros : preserve BC 2.1
  • cons : Lots of methods might not work as expected (hasBeenSignaled, getTermSignal, hasBeenStopped, getStopSignal, stop)

Split commands in atomic subprocesses / add a chain method / enforce use of ProcessBuilder

  • pros : guarantee the control control over the processes, adds multiple possibilities for chaining strategies), fixes
  • cons : breaks the BC with 2.1, disable the ability to run chained commands in the background (There is no way to add a callback when a process finish to start the next one)

Do you have any thoughts about this ?

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions