Comments

greg.1.anderson’s picture

Status: Active » Needs review
StatusFileSize
new980 bytes

Here's a first attempt, completely untested.

tstoeckler’s picture

Now getting fatal: Undefined function drush_backend_invoke_args()
It should be possible to replace that with drush_invoke_process(), too, though, right?

EDIT: Sorry, wrong issue.

tstoeckler’s picture

Hmm.. this isn't working for me.
I also tried bringing the exact Drush 4 behavior back á la:

$exec_cmd = '(' . $exec_cmd . ' &) > /dev/null';
drush_op_system($exec_cmd);
return;

(Just like in http://api.drush.org/api/function/drush_backend_fork/4.x)
but that didn't work either.

That said, is there any more reliabe way to test this? Currently I'm just using Aegir with the patch over at #1433406: Make hosting (specifically hosting-dispatch) work with Drush 5, but, as before, what happens is that the tests run through, but the Task isn't marked as comleted, i.e. the spinner keeps spinning. That's probably not the most reliable way to test this, though.

greg.1.anderson’s picture

It does not appear to be possible to run Drush in the background. To whit:

$ drush version &
[1] 30693
$ 

[1]+  Stopped                 drush version
$ fg
drush version
drush version 5.0-dev

Contrast with:

$ pwd &
[1] 30778
/home/ga/local/drush
[1]+  Done                    pwd

Most shell commands, when run in the background, behave like the second example. They run, they complete, they print "Done". Something that drush is doing causes it to stop. It's not in the bash wrapper; /usr/bin/php /home/ga/local/drush/drush.php --php=/usr/bin/php version --debug & also stops prior to producing any output. I presume this is related to:

Background processes which attempt to read from (write to when stty tostop is in effect) the terminal are sent a SIGTTIN (SIGTTOU) signal by the kernel's terminal driver, which, unless caught, suspends the process.

This would be perfectly understandable if Drush was being called with --backend, but I don't think that Drush reads from stdin unless --backend is specified.

However, it also appears that Drush-4.x behaves the same way. Does Aegir work on the HEAD of Drush-4.x with drush_backend_fork? I presume that it does; perhaps there is something wrong with my experiments, then? No time to trace this farther right now.

alexpott’s picture

The patch in #1 works fine for me running following code using the command "drush scr fork5.php". With the patch we get 10 simultaneous processes as expected.

$fork = drush_get_option('forktest');
$pid = getmypid();
$ourFileName = dirname(__FILE__) . "/fork-$fork-pid-$pid";
$ourFileHandle = fopen($ourFileName, 'w') or die("can't open file");
fclose($ourFileHandle);
$fork++;
if ($fork < 10) {
  drush_invoke_process('@none', 'scr', array(dirname(__FILE__) . '/fork5.php'), array('forktest' => $fork), array('fork' => TRUE));
}

I've tested this on both Centos 5.2 and Mac OS X Lion... it works as expected on both OSes. Interesting on Centos:

$drush version &
[1] 3430
drush version 5.0-dev

[1]+  Done                    ~/dev/drush5/drush version

On MacOS X it exhibits the behaviour Greg described above - stopping until the command fg is used.

alexpott’s picture

greg.1.anderson’s picture

Status: Needs review » Needs work

Setting status until we can figure out what is going on with the blocking behavior.

alexpott’s picture

Hi Greg,

This is not an issue for drush but occurs for all php commands run from the command line.

If you create a php script test.php as

  print 1;

Try running php test.php & it hangs too on Mac OS X

Run it using thisphp test.php < /dev/null & and it does not

Same for drush version < /dev/null &

alexpott’s picture

Afaik there is one outstanding issue for the patch in #1. When running the test described in #5 under drush5 lots of output is written to stdout which is not the case with drush4.

Is this a desired effect of the changes to backend.inc in drush5?

alexpott’s picture

Status: Needs work » Needs review
StatusFileSize
new2.17 KB

This patch only prints backend output for forked processes if the verbose or debug options are set.

I think this patch is good to go.

tstoeckler’s picture

@alexpott: Is there a specific way to test your patch?

Also, I cannot reproduce #8. It hangs for me either way...

greg.1.anderson’s picture

Status: Needs review » Needs work

The 'exit' in drush_backend_output is disquieting. Could this be done another way? At the very least it needs more explanation.

I tried #8, and it worked for me exactly as described. I'm on Ubuntu Linux. @tstoeckler: what platform did you test?

There does not seem to be any /dev/null input redirection in #10.

tstoeckler’s picture

I'm on Debian 6.
I tried #8 again, and it works for me if you redirect the output to /dev/null. Redirecting the input doesn't work. Hmm..

greg.1.anderson’s picture

Using a test.php that just prints one line (with a newline), this is what I am seeing:

$ php test.php < /dev/null &
[1] 4662
$ wow

The php program prints "wow" above. Then I must press [Enter] to see the done message:

[1]+  Done                    php test.php < /dev/null
$ php test.php > /dev/null &
[1] 4674
$ 

[1]+  Stopped                 php test.php > /dev/null
$ fg
php test.php > /dev/null

As you can see, redirecting output does not prevent php from hanging in my tests. I don't have a Debian 6 install handy, but I have no theories about why your results should be different.

Oh, we could also use a backend fork unit test for #10.

alexpott’s picture

Greg #12 - how right you are that was meant to be a return not an exit.

Anyhow I think the patch attached is a "cleaner" solution using a helper function - drush_backend_check_output() - to determine if the backend process should print to stdout.

Working some tests...

greg.1.anderson’s picture

Is it unnecessary to redirect input from /dev/null if all output is suppressed? Code is looking better, but still needs a unit test.

tstoeckler’s picture

Then I must press [Enter] to see the done message

Ahh, I didn't know that was the wanted behavior. (I told you I was a noob :)...)

Yes, I can reproduce exactly what you describe.

alexpott’s picture

Status: Needs work » Needs review
StatusFileSize
new3.63 KB

Patch now with added test goodness...

The test invokes a forked process that creates a file after a second in PHPUnit's sandbox folder. Meanwhile the test checks for the existence of this file then waits for 2 seconds and checks again.

greg.1.anderson’s picture

Status: Needs review » Needs work

Looks good, but can we write the test file to UNISH_TMP instead of cwd?

alexpott’s picture

StatusFileSize
new3.56 KB

No problem... didn't know about UNISH_TMP :)

alexpott’s picture

StatusFileSize
new3.57 KB

Changed to use UNISH_SANDBOX as that seems more consistent will other tests that are creating files eg. testArchiveDump

alexpott’s picture

Status: Needs work » Needs review

Updating issue status...

moshe weitzman’s picture

Status: Needs review » Needs work

We need to document the 'fork' backend option. I'd like to state why one would use it, in addition to stating what it does.

alexpott’s picture

Status: Needs work » Needs review
StatusFileSize
new4.32 KB

Good point. Patch now includes documentation...

moshe weitzman’s picture

How does fork help with 'Can be used to write commands that restart themselves before they run out of memory.'. We already do that with regular backend calls. See updatedb and migrate-import in migrate module. Furthermore, please state what happens with integrating results from forked calls. Return values are ignored?

moshe weitzman’s picture

Status: Needs review » Needs work

CNW for docs

tstoeckler’s picture

I tried to get this to work, but am getting a weird error:
When I verify a site, it re-saves the corresponding alias with the wrong path to the site. Namely it always uses the main hostmaster platform as a site path (i.e. /var/aegir/hostmaster-1.6/sites/foo instead of /var/aegir/platforms/bar/sites/foo).

So my question regarding drush_invoke_process is about the provision-save command. It takes an alias as an argument, so I don't know what to put in the $alias argument for drush_invoke_process.

// Is it this...
drush_invoke_process($alias, 'provision-save', array($alias), ...);

// ...or is it this?
drush_invoke_process('@self', 'provision-save', array($alias), ...);

I currently use '@self', because I thought it shouldn't really matter, but that does not seem to work. It may, of course, very well be, that my problem is caused by something else, but I thought I'd ask.

greg.1.anderson’s picture

'@self' means the bootstrapped site. '@none' means no site. array('root' => '/path/to/drupal', 'uri' => 'mydrupalsite.org') to specify some other site. I'm not familiar with hostmaster, but if provision-save is taking an alias as the first parameter, maybe '@none' is what you want here. You should probably put hostmatster support requests in separate issues in the hostmaster queue, though.

tstoeckler’s picture

Thanks, I'll try that.
Yes, I first wanted to post this issue in the Hostmaster queue, but since this is specific to the Drush 5 port...
I'll still try to get this to work in the next few days, but for what its worth, the tasks now actually complete fully, so it seems the 'forking' part seems to work.
/me shuts up now to let the big guys fix this :)

alexpott’s picture

Status: Needs work » Needs review
StatusFileSize
new4.37 KB

Patch attached for another go at documentation. My primary use case for this functionality is http://drupal.org/project/drushd. This needs to be able to fork a process in a non-blocking way to allow daemon threads to refork safely.

The new documentation from the patch:

/**
 *      'fork'
 *        Overrides the backend invoke process to run non blocking commands in 
 *        the background. Forks a new process by adding a '&' at the end of the 
 *        command. The calling process does not receive any output from the child 
 *        process. The fork option is used to spawn a process that outlives its
 *        parent.
 */
greg.1.anderson’s picture

Status: Needs review » Needs work
StatusFileSize
new3.04 KB

I know I passed this in #20, but I've been looking at the backend code a lot today, and therefore have more opinions. :p Could we get rid of the --backend-fork option? --backend is not even used with the 'fork' option, so this seems unnecessary. I added --quiet for good measure, to reinforce the concept that you don't get the output in fork mode anyway. This does not stop the log messages from printing, but that does not affect the tests, so I think it is okay. Patch attached.

greg.1.anderson’s picture

Status: Needs work » Needs review

I decided to provide a patch, but forgot to set status back to 'needs review'.

moshe weitzman’s picture

Status: Needs review » Reviewed & tested by the community

Looks fine. Perhaps use http://php.net/manual/en/function.usleep.php in order to wait less.

greg.1.anderson’s picture

Committed with reduced sleep time. A milisecond in the subprocess was long enough to insure that the file did not exist to begin with; I did not feel inclined to tune it down any lower than that. I got failures with sleep times around a quarter of a second before checking to see if the file had been created, but it always worked at half a second. I did not try to tune it any closer than that, as we may get false failures on slow systems, or during load spikes. I suppose it would be better to sleep-and-check and sleep-and-check, and succeed when it shows up, or fail after some longer delay (a second or two), but didn't feel like being that involved with it.

greg.1.anderson’s picture

Status: Reviewed & tested by the community » Fixed

Set status.

greg.1.anderson’s picture

I went back and added the 'for' loop per #35 so that the test does not need to wait longer than necessary.

Status: Fixed » Closed (fixed)

Automatically closed -- issue fixed for 2 weeks with no activity.