Skip to content
Merged
28 changes: 28 additions & 0 deletions features/cron-event.feature
Original file line number Diff line number Diff line change
Expand Up @@ -244,3 +244,31 @@ Feature: Manage WP Cron events
"""
Debug: Beginning execution of cron event 'wp_version_check'
"""

Scenario: --due-now respects the doing_cron transient and skips when another run is in progress
When I run `wp cron event schedule wp_cli_test_event_lock now hourly`
Then STDOUT should contain:
"""
Success: Scheduled event with hook 'wp_cli_test_event_lock'
"""

# Simulate an in-progress cron run by setting the doing_cron transient.
When I run `wp eval 'set_transient( "doing_cron", sprintf( "%.22F", microtime( true ) ) );'`

And I try `wp cron event run --due-now`
Then STDERR should contain:
"""
Warning: A cron event run is already in progress; skipping.
"""
And STDOUT should not contain:
"""
wp_cli_test_event_lock
"""

# After the transient is cleared, the run should proceed normally.
When I run `wp eval 'delete_transient( "doing_cron" );'`
And I try `wp cron event run --due-now`
Then STDOUT should contain:
"""
Executed the cron event 'wp_cli_test_event_lock'
"""
7 changes: 6 additions & 1 deletion features/cron.feature
Original file line number Diff line number Diff line change
Expand Up @@ -307,8 +307,13 @@ Feature: Manage WP-Cron events and schedules
# executes the "wp_privacy_delete_old_export_files" event there.
@require-wp-5.0
Scenario: Run currently scheduled events
# Disable web-triggered cron so spawn_cron() cannot set doing_cron between
# steps - wp cron event run always defines DOING_CRON so this has no effect
# on the commands being tested.
When I run `wp config set DISABLE_WP_CRON true --raw`

# WP throws a notice here for older versions of core.
When I try `wp cron event run --all`
And I try `wp cron event run --all`
Then STDOUT should contain:
"""
Executed the cron event 'wp_version_check'
Expand Down
24 changes: 23 additions & 1 deletion src/Cron_Event_Command.php
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,8 @@ public function schedule( $args, $assoc_args ) {
* : One or more hooks to run.
*
* [--due-now]
* : Run all hooks due right now.
* : Run all hooks due right now. Respects the doing_cron transient to
* prevent overlapping runs.
*
* [--exclude=<hooks>]
* : Comma-separated list of hooks to exclude.
Expand All @@ -243,10 +244,27 @@ public function schedule( $args, $assoc_args ) {
* Success: Executed a total of 2 cron events.
*/
public function run( $args, $assoc_args ) {
$due_now = Utils\get_flag_value( $assoc_args, 'due-now' );

$doing_cron_value = null;

if ( $due_now ) {
$lock_timeout = defined( 'WP_CRON_LOCK_TIMEOUT' ) ? WP_CRON_LOCK_TIMEOUT : 60;
$doing_cron_transient = get_transient( 'doing_cron' );
if ( is_numeric( $doing_cron_transient ) && (float) $doing_cron_transient > microtime( true ) - $lock_timeout ) {
WP_CLI::warning( 'A cron event run is already in progress; skipping.' );
return;
}
$doing_cron_value = sprintf( '%.22F', microtime( true ) );
set_transient( 'doing_cron', $doing_cron_value, $lock_timeout );
}

$events = self::get_selected_cron_events( $args, $assoc_args );

if ( is_wp_error( $events ) ) {
if ( $due_now && get_transient( 'doing_cron' ) === $doing_cron_value ) {
delete_transient( 'doing_cron' );
}
WP_CLI::error( $events );
}

Expand All @@ -263,6 +281,10 @@ public function run( $args, $assoc_args ) {
}
}

if ( $due_now && get_transient( 'doing_cron' ) === $doing_cron_value ) {
delete_transient( 'doing_cron' );
}

$message = ( 1 === $executed ) ? 'Executed a total of %d cron event.' : 'Executed a total of %d cron events.';
WP_CLI::success( sprintf( $message, $executed ) );
}
Expand Down