Improve cron locking. Avoid multiple cron processes looping over the same events. fixes #17462
git-svn-id: http://svn.automattic.com/wordpress/trunk@18659 1a063a9b-81f0-0310-95a4-ce76da25c4cd
This commit is contained in:
parent
01073d5f3c
commit
5ebcc1d3ea
56
wp-cron.php
56
wp-cron.php
|
@ -26,6 +26,24 @@ if ( !defined('ABSPATH') ) {
|
||||||
require_once('./wp-load.php');
|
require_once('./wp-load.php');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Uncached doing_cron transient fetch
|
||||||
|
function _get_cron_lock() {
|
||||||
|
global $_wp_using_ext_object_cache, $wpdb;
|
||||||
|
|
||||||
|
$value = 0;
|
||||||
|
if ( $_wp_using_ext_object_cache ) {
|
||||||
|
// Skip local cache and force refetch of doing_cron transient in case
|
||||||
|
// another processs updated the cache
|
||||||
|
$value = wp_cache_get( 'doing_cron', 'transient', true );
|
||||||
|
} else {
|
||||||
|
$row = $wpdb->get_row( $wpdb->prepare( "SELECT option_value FROM $wpdb->options WHERE option_name = %s LIMIT 1", '_transient_doing_cron' ) );
|
||||||
|
if ( is_object( $row ) )
|
||||||
|
$value = $row->option_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $value;
|
||||||
|
}
|
||||||
|
|
||||||
if ( false === $crons = _get_cron_array() )
|
if ( false === $crons = _get_cron_array() )
|
||||||
die();
|
die();
|
||||||
|
|
||||||
|
@ -35,26 +53,52 @@ $local_time = time();
|
||||||
if ( isset($keys[0]) && $keys[0] > $local_time )
|
if ( isset($keys[0]) && $keys[0] > $local_time )
|
||||||
die();
|
die();
|
||||||
|
|
||||||
foreach ($crons as $timestamp => $cronhooks) {
|
$doing_cron_transient = get_transient( 'doing_cron');
|
||||||
|
|
||||||
|
// Use global $doing_wp_cron lock otherwise use the GET lock. If no lock, trying grabbing a new lock.
|
||||||
|
if ( empty( $doing_wp_cron ) ) {
|
||||||
|
if ( empty( $_GET[ 'doing_wp_cron' ] ) ) {
|
||||||
|
// Called from external script/job. Try setting a lock.
|
||||||
|
if ( $doing_cron_transient && ( $doing_cron_transient + WP_CRON_LOCK_TIMEOUT > $local_time ) )
|
||||||
|
return;
|
||||||
|
$doing_cron_transient = $doing_wp_cron = time();
|
||||||
|
set_transient( 'doing_cron', $doing_wp_cron );
|
||||||
|
} else {
|
||||||
|
$doing_wp_cron = $_GET[ 'doing_wp_cron' ];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check lock
|
||||||
|
if ( $doing_cron_transient != $doing_wp_cron )
|
||||||
|
return;
|
||||||
|
|
||||||
|
foreach ( $crons as $timestamp => $cronhooks ) {
|
||||||
if ( $timestamp > $local_time )
|
if ( $timestamp > $local_time )
|
||||||
break;
|
break;
|
||||||
|
|
||||||
foreach ($cronhooks as $hook => $keys) {
|
foreach ( $cronhooks as $hook => $keys ) {
|
||||||
|
|
||||||
foreach ($keys as $k => $v) {
|
foreach ( $keys as $k => $v ) {
|
||||||
|
|
||||||
$schedule = $v['schedule'];
|
$schedule = $v['schedule'];
|
||||||
|
|
||||||
if ($schedule != false) {
|
if ( $schedule != false ) {
|
||||||
$new_args = array($timestamp, $schedule, $hook, $v['args']);
|
$new_args = array($timestamp, $schedule, $hook, $v['args']);
|
||||||
call_user_func_array('wp_reschedule_event', $new_args);
|
call_user_func_array('wp_reschedule_event', $new_args);
|
||||||
}
|
}
|
||||||
|
|
||||||
wp_unschedule_event($timestamp, $hook, $v['args']);
|
wp_unschedule_event( $timestamp, $hook, $v['args'] );
|
||||||
|
|
||||||
do_action_ref_array($hook, $v['args']);
|
do_action_ref_array( $hook, $v['args'] );
|
||||||
|
|
||||||
|
// If the hook ran too long and another cron process stole the lock, quit.
|
||||||
|
if ( _get_cron_lock() != $doing_wp_cron )
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( _get_cron_lock() == $doing_wp_cron )
|
||||||
|
delete_transient( 'doing_cron' );
|
||||||
|
|
||||||
die();
|
die();
|
||||||
|
|
|
@ -102,13 +102,14 @@ function wp_cache_flush() {
|
||||||
*
|
*
|
||||||
* @param int|string $key What the contents in the cache are called
|
* @param int|string $key What the contents in the cache are called
|
||||||
* @param string $group Where the cache contents are grouped
|
* @param string $group Where the cache contents are grouped
|
||||||
|
* @param bool $force Whether to force an update of the local cache from the persistent cache (default is false)
|
||||||
* @return bool|mixed False on failure to retrieve contents or the cache
|
* @return bool|mixed False on failure to retrieve contents or the cache
|
||||||
* contents on success
|
* contents on success
|
||||||
*/
|
*/
|
||||||
function wp_cache_get($key, $group = '') {
|
function wp_cache_get( $key, $group = '', $force = false ) {
|
||||||
global $wp_object_cache;
|
global $wp_object_cache;
|
||||||
|
|
||||||
return $wp_object_cache->get($key, $group);
|
return $wp_object_cache->get( $key, $group, $force );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -403,10 +404,11 @@ class WP_Object_Cache {
|
||||||
*
|
*
|
||||||
* @param int|string $key What the contents in the cache are called
|
* @param int|string $key What the contents in the cache are called
|
||||||
* @param string $group Where the cache contents are grouped
|
* @param string $group Where the cache contents are grouped
|
||||||
|
* @param string $force Whether to force a refetch rather than relying on the local cache (default is false)
|
||||||
* @return bool|mixed False on failure to retrieve contents or the cache
|
* @return bool|mixed False on failure to retrieve contents or the cache
|
||||||
* contents on success
|
* contents on success
|
||||||
*/
|
*/
|
||||||
function get($key, $group = 'default') {
|
function get( $key, $group = 'default', $force = false) {
|
||||||
if ( empty ($group) )
|
if ( empty ($group) )
|
||||||
$group = 'default';
|
$group = 'default';
|
||||||
|
|
||||||
|
|
|
@ -204,13 +204,13 @@ function spawn_cron( $local_time = 0 ) {
|
||||||
* multiple processes on multiple web servers can run this code concurrently
|
* multiple processes on multiple web servers can run this code concurrently
|
||||||
* try to make this as atomic as possible by setting doing_cron switch
|
* try to make this as atomic as possible by setting doing_cron switch
|
||||||
*/
|
*/
|
||||||
$flag = get_transient('doing_cron');
|
$lock = get_transient('doing_cron');
|
||||||
|
|
||||||
if ( $flag > $local_time + 10*60 )
|
if ( $lock > $local_time + 10*60 )
|
||||||
$flag = 0;
|
$lock = 0;
|
||||||
|
|
||||||
// don't run if another process is currently running it or more than once every 60 sec.
|
// don't run if another process is currently running it or more than once every 60 sec.
|
||||||
if ( $flag + 60 > $local_time )
|
if ( $lock + WP_CRON_LOCK_TIMEOUT > $local_time )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
//sanity check
|
//sanity check
|
||||||
|
@ -226,10 +226,11 @@ function spawn_cron( $local_time = 0 ) {
|
||||||
if ( !empty($_POST) || defined('DOING_AJAX') )
|
if ( !empty($_POST) || defined('DOING_AJAX') )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
set_transient( 'doing_cron', $local_time );
|
$doing_wp_cron = $local_time;
|
||||||
|
set_transient( 'doing_cron', $doing_wp_cron );
|
||||||
|
|
||||||
ob_start();
|
ob_start();
|
||||||
wp_redirect( add_query_arg('doing_wp_cron', '', stripslashes($_SERVER['REQUEST_URI'])) );
|
wp_redirect( add_query_arg('doing_wp_cron', $doing_wp_cron, stripslashes($_SERVER['REQUEST_URI'])) );
|
||||||
echo ' ';
|
echo ' ';
|
||||||
|
|
||||||
// flush any buffers and send the headers
|
// flush any buffers and send the headers
|
||||||
|
@ -240,9 +241,10 @@ function spawn_cron( $local_time = 0 ) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
set_transient( 'doing_cron', $local_time );
|
$doing_wp_cron = $local_time;
|
||||||
|
set_transient( 'doing_cron', $doing_wp_cron );
|
||||||
|
|
||||||
$cron_url = get_option( 'siteurl' ) . '/wp-cron.php?doing_wp_cron';
|
$cron_url = get_option( 'siteurl' ) . '/wp-cron.php?doing_wp_cron=' . $doing_wp_cron;
|
||||||
wp_remote_post( $cron_url, array('timeout' => 0.01, 'blocking' => false, 'sslverify' => apply_filters('https_local_ssl_verify', true)) );
|
wp_remote_post( $cron_url, array('timeout' => 0.01, 'blocking' => false, 'sslverify' => apply_filters('https_local_ssl_verify', true)) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -268,6 +268,12 @@ function wp_functionality_constants( ) {
|
||||||
|
|
||||||
if ( !defined('WP_POST_REVISIONS') )
|
if ( !defined('WP_POST_REVISIONS') )
|
||||||
define('WP_POST_REVISIONS', true);
|
define('WP_POST_REVISIONS', true);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @since 3.3.0
|
||||||
|
*/
|
||||||
|
if ( !defined( 'WP_CRON_LOCK_TIMEOUT' ) )
|
||||||
|
define('WP_CRON_LOCK_TIMEOUT', 60); // In seconds
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in New Issue