Automatic cron is invoked during a page request, and for as long as cron is running, the page does not get sent to the browser. This can cause a significant delay in the page being rendered. This can be seen by putting a call to sleep(25) in hook_cron.

Also, if an error is encountered during cron invocation, it can output error text at the bottom of the rendered page. This can be seen by simply throwing an exception in hook_cron.

Both of these issues can be addressed by running cron in a separate process, forked from the process servicing the request. Not all environments are configured to make this possible; the Process Control extension must be installed in order for php to make use of fork.

For environments that do not support forking, we can gracefully fall back to the current behavior.

See the attached image for an example of an error message being appended to the display.

Comments

paul.lovvik’s picture

Status: Active » Needs review
StatusFileSize
new6.13 KB

This patch uses pcntl_fork to accomplish running cron in a separate process. If the pcntl_fork function is not available, drupal_cron_run is executed in the same process. This ensures a basic cron functionality is always available.

The test had to be modified slightly to grab the value of the 'cron_test' variable directly from the database because the value is updated in the child process and the value has already been cached in the parent process.

Using this patch, the requested page returns immediately, and any errors encountered during cron execution have no way of affecting the rendered page.

dries’s picture

This is nifty and superior to doing cron as part of the same page request.

This would be a great solution for Drupal Gardens as we don't have to setup 25,000 crontabs. :P

David_Rothstein’s picture

Title: Run cron in a separate process to avoid a response delay and an error message being appended to the page. » Run cron in a separate process to avoid a response delay
Version: 7.0-beta2 » 7.x-dev
Priority: Major » Normal

I think the error message being appended to the display is its own bug that needs a more general solution. I created one here: #963206: Errors thrown during automated cron result in an extra error page appended at the bottom of the normal one

As for this patch, one big question... Do you know why the PCNTL manual (http://www.php.net/manual/en/intro.pcntl.php) says this?:

Process Control should not be enabled within a web server environment and unexpected results may happen if any Process Control functions are used within a web server environment.

That is very vague, but certainly sounds ominous :)

***

I remember with some fondness our attempt around a year ago to do this via the "Connection: close" method:
http://drupal.org/node/566494#comment-2115892

That did not work in every server configuration, but it had the advantage of working in many common ones (for example, it worked just fine on my laptop's default Apache installation). However, we did not test it extensively enough to know if had any undesired side effects.

mark trapp’s picture

The comments on pcntl_fork() shed a little more light on that ominous message:

you should be _very_ careful with using fork in scripts beyond academic examples, or rather just avoid it alltogether, unless you are very aware of it's limitations.

the problem is that it just forks the whole php process, including not only the state of the script, but also the internal state of any extensions loaded.
this means that all memory is copied, but all file descriptors are shared among the parent and child processes. and that can cause major havoc if some extension internally maintains file descriptors. the primary example is ofcourse mysql, but this could be any extensions that maintains open files or network sockets. also, just reopening your connection in the parent or child isn't a safe method, because when the old connection resource is destroyed, the extension might not just close it, but for example send a request to the server to log off, making the connection unusable.

There are a few suggested workarounds for MySQL, but it doesn't seem to be as cut-and-dry as merely checking to see if pcntl_fork() exists (this patch does look like it's attempting to handle that, though).

damien tournoud’s picture

Version: 7.x-dev » 8.x-dev
Category: bug » feature

That's a feature request, bumping to D8. We cannot change this so late in the cycle, and this only affect a page once in a blue moon.

mattis’s picture

A few notes regarding this, fyi as I was experimenting with pcntl_fork in cron as well:

pcntl_fork runs only for CGI or CLI:
http://php.net/manual/en/function.pcntl-fork.php#49949
although this is handled in the patch by calling function_exists, the patch won't have the desired effect in a lot of cases.

I'm not sure, if it's enough to close the database within the child process only and leaving it open in the parent process. If the parent want's to use the database afterwards and the connection was closed by the child... couldn't this lead to race conditions which could be avoided by closing the connection just right before forking and therefore force parent and child to open a new database connection? (That's how I'm handling it)

gielfeldt’s picture

In my experience forking can be dangerous or at least cause side effects (expected or unexecpted). Nevertheless, when using fork, there's always a lot of things to consider, in order to remedy these side effects, and you might end up with much more bug-fixing than you bargained for. Besides that, there's also the platform issue, not only *nix/windows but also cgi/cli only as already mentioned.

Ultimate Cron implements a background process driven poormans cron, by issuing a new http request without waiting for the response, thereby detaching it from the users request.

I would like to see something like this in Drupal 8.

catch’s picture

Cross posting #1189464: Add an 'instant' queue runner.

Not sure what ultimate cron uses, but the approach sounds similar to

https://github.com/biznickman/PHP-Async

http://drupal.org/project/httprl

linked from that issue too. Given the constraints of having to trigger cron from http requests in the first place (i.e. not from cron or jenkins or anywhere like that), then the non-blocking http request seems like a good way to handle this, and is not something I remember being discussed in the original issue.

gielfeldt’s picture

Ultimate Cron uses the same technique (through Background Brocess which is somewhat similar to httprl). I've heard of ideas using a 1px gif for this, and it doesn't sit well with me.

Another technique I've considered for poormans cron, is doing a combination of:
* Connection: Close
* a specified Content-Length
* user_ignore_abort(TRUE)
* set_time_limit(very-high)

in order for the client to detach and for the cron stuff to commence.
This could save an extra http request while still not affecting the users.

catch’s picture

Both the 1px gif and Connection: Close with specified content length in one of the original poormanscron core issues and rejected. Core was originally doing 1px gif but that caused an additional http request and full bootstrap on every single request to Drupal including cached ones so was removed in favour of what we have now (which makes the request that runs cron very slow but doesn't mess everything else up). The content length stuff sounded great but I remember David Rothstein had trouble getting it actually working reliably.

robloach’s picture

Status: Needs review » Needs work

This most likely needs a re-roll.

David_Rothstein’s picture

Related (and might supersede this one): #1599622: Run poormanscron via a non-blocking HTTP request

Version: 8.0.x-dev » 8.1.x-dev

Drupal 8.0.6 was released on April 6 and is the final bugfix release for the Drupal 8.0.x series. Drupal 8.0.x will not receive any further development aside from security fixes. Drupal 8.1.0-rc1 is now available and sites should prepare to update to 8.1.0.

Bug reports should be targeted against the 8.1.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.2.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.1.x-dev » 8.2.x-dev

Drupal 8.1.9 was released on September 7 and is the final bugfix release for the Drupal 8.1.x series. Drupal 8.1.x will not receive any further development aside from security fixes. Drupal 8.2.0-rc1 is now available and sites should prepare to upgrade to 8.2.0.

Bug reports should be targeted against the 8.2.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.3.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.2.x-dev » 8.3.x-dev

Drupal 8.2.6 was released on February 1, 2017 and is the final full bugfix release for the Drupal 8.2.x series. Drupal 8.2.x will not receive any further development aside from critical and security fixes. Sites should prepare to update to 8.3.0 on April 5, 2017. (Drupal 8.3.0-alpha1 is available for testing.)

Bug reports should be targeted against the 8.3.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.4.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.3.x-dev » 8.4.x-dev

Drupal 8.3.6 was released on August 2, 2017 and is the final full bugfix release for the Drupal 8.3.x series. Drupal 8.3.x will not receive any further development aside from critical and security fixes. Sites should prepare to update to 8.4.0 on October 4, 2017. (Drupal 8.4.0-alpha1 is available for testing.)

Bug reports should be targeted against the 8.4.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.5.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.4.x-dev » 8.5.x-dev

Drupal 8.4.4 was released on January 3, 2018 and is the final full bugfix release for the Drupal 8.4.x series. Drupal 8.4.x will not receive any further development aside from critical and security fixes. Sites should prepare to update to 8.5.0 on March 7, 2018. (Drupal 8.5.0-alpha1 is available for testing.)

Bug reports should be targeted against the 8.5.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.6.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.5.x-dev » 8.6.x-dev

Drupal 8.5.6 was released on August 1, 2018 and is the final bugfix release for the Drupal 8.5.x series. Drupal 8.5.x will not receive any further development aside from security fixes. Sites should prepare to update to 8.6.0 on September 5, 2018. (Drupal 8.6.0-rc1 is available for testing.)

Bug reports should be targeted against the 8.6.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.7.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.6.x-dev » 8.8.x-dev

Drupal 8.6.x will not receive any further development aside from security fixes. Bug reports should be targeted against the 8.8.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.9.x-dev branch. For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

Version: 8.8.x-dev » 8.9.x-dev

Drupal 8.8.7 was released on June 3, 2020 and is the final full bugfix release for the Drupal 8.8.x series. Drupal 8.8.x will not receive any further development aside from security fixes. Sites should prepare to update to Drupal 8.9.0 or Drupal 9.0.0 for ongoing support.

Bug reports should be targeted against the 8.9.x-dev branch from now on, and new development or disruptive changes should be targeted against the 9.1.x-dev branch. For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

Version: 8.9.x-dev » 9.2.x-dev

Drupal 8 is end-of-life as of November 17, 2021. There will not be further changes made to Drupal 8. Bugfixes are now made to the 9.3.x and higher branches only. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.2.x-dev » 9.3.x-dev

Version: 9.3.x-dev » 9.4.x-dev

Drupal 9.3.15 was released on June 1st, 2022 and is the final full bugfix release for the Drupal 9.3.x series. Drupal 9.3.x will not receive any further development aside from security fixes. Drupal 9 bug reports should be targeted for the 9.4.x-dev branch from now on, and new development or disruptive changes should be targeted for the 9.5.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.4.x-dev » 9.5.x-dev

Drupal 9.4.9 was released on December 7, 2022 and is the final full bugfix release for the Drupal 9.4.x series. Drupal 9.4.x will not receive any further development aside from security fixes. Drupal 9 bug reports should be targeted for the 9.5.x-dev branch from now on, and new development or disruptive changes should be targeted for the 10.1.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

berdir’s picture

Issue summary: View changes
Status: Needs work » Closed (duplicate)

Yes, I agree this is a duplicate of #12. Which we also weren't able to get working until now. There was no update on this issue in 10 years, lets just close it?

I'm not sure if automated cron even was a standalone module back then, it is now and anyone who is able to have a proper cron set up should absolutely not rely on it and uninstall it. Maybe we could do a better job at explaining this. Still seeing too many people confused about that admin setting and what it does.