Make WordPress Core

Changeset 43050


Ignore:
Timestamp:
05/01/2018 02:04:25 AM (7 years ago)
Author:
peterwilsoncc
Message:

Cron API: Return meaningful values from cron functions.

Return values added to Cron API functions to indicate outcome:

  • wp_schedule_single_event(), wp_schedule_event(), wp_reschedule_event() and wp_unschedule_event(): boolean indicating success or failure,
  • wp_clear_scheduled_hook(): integer indicating number of jobs cleared (zero or more), false if one or more jobs fail to clear,
  • wp_unschedule_hook(): integer indicating number of jobs cleared (zero or more), false if the jobs fail to clear,
  • spawn_cron(): boolean indicating whether job spawned,
  • wp_cron(): integer indicating number of jobs spawned (zero or more), false if one or more jobs fail to spawned,
  • _set_cron_array(): boolean outcome of update_option().

Props evansolomon, jrf, peterwilsoncc, pento for code review.
Fixes #21072.

Location:
trunk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/cron.php

    r42343 r43050  
    2222 *
    2323 * @since 2.1.0
     24 * @since 5.0.0 Return value modified to boolean indicating success or failure.
     25 *
    2426 * @link https://codex.wordpress.org/Function_Reference/wp_schedule_single_event
    2527 *
     
    2729 * @param string $hook       Action hook to execute when the event is run.
    2830 * @param array  $args       Optional. Array containing each separate argument to pass to the hook's callback function.
    29  * @return false|void False if the event did not get scheduled.
     31 * @return bool True if event successfully scheduled. False for failure.
    3032 */
    3133function wp_schedule_single_event( $timestamp, $hook, $args = array() ) {
     
    7880    );
    7981    uksort( $crons, 'strnatcasecmp' );
    80     _set_cron_array( $crons );
     82    return _set_cron_array( $crons );
    8183}
    8284
     
    100102 *
    101103 * @since 2.1.0
     104 * @since 5.0.0 Return value modified to boolean indicating success or failure.
     105 *
    102106 * @link https://codex.wordpress.org/Function_Reference/wp_schedule_event
    103107 *
     
    106110 * @param string $hook       Action hook to execute when the event is run.
    107111 * @param array  $args       Optional. Array containing each separate argument to pass to the hook's callback function.
    108  * @return false|void False if the event did not get scheduled.
     112 * @return bool True if event successfully scheduled. False for failure.
    109113 */
    110114function wp_schedule_event( $timestamp, $recurrence, $hook, $args = array() ) {
     
    144148    );
    145149    uksort( $crons, 'strnatcasecmp' );
    146     _set_cron_array( $crons );
     150    return _set_cron_array( $crons );
    147151}
    148152
     
    151155 *
    152156 * @since 2.1.0
     157 * @since 5.0.0 Return value modified to boolean indicating success or failure.
    153158 *
    154159 * @param int    $timestamp  Unix timestamp (UTC) for when to next run the event.
     
    156161 * @param string $hook       Action hook to execute when the event is run.
    157162 * @param array  $args       Optional. Array containing each separate argument to pass to the hook's callback function.
    158  * @return false|void False if the event did not get rescheduled.
     163 * @return bool True if event successfully rescheduled. False for failure.
    159164 */
    160165function wp_reschedule_event( $timestamp, $recurrence, $hook, $args = array() ) {
     
    190195    }
    191196
    192     wp_schedule_event( $timestamp, $recurrence, $hook, $args );
     197    return wp_schedule_event( $timestamp, $recurrence, $hook, $args );
    193198}
    194199
     
    200205 *
    201206 * @since 2.1.0
     207 * @since 5.0.0 Return value modified to boolean indicating success or failure.
    202208 *
    203209 * @param int    $timestamp Unix timestamp (UTC) of the event.
     
    206212 *                          Although not passed to a callback, these arguments are used to uniquely identify the
    207213 *                          event, so they should be the same as those used when originally scheduling the event.
    208  * @return false|void False if the event did not get unscheduled.
     214 * @return bool True if event successfully unscheduled. False for failure.
    209215 */
    210216function wp_unschedule_event( $timestamp, $hook, $args = array() ) {
     
    223229        unset( $crons[ $timestamp ] );
    224230    }
    225     _set_cron_array( $crons );
     231    return _set_cron_array( $crons );
    226232}
    227233
     
    229235 * Unschedules all events attached to the hook with the specified arguments.
    230236 *
    231  * @since 2.1.0
     237 * Warning: This function may return Boolean FALSE, but may also return a non-Boolean
     238 * value which evaluates to FALSE. For information about casting to booleans see the
     239 * {@link https://php.net/manual/en/language.types.boolean.php PHP documentation}. Use
     240 * the `===` operator for testing the return value of this function.
     241 *
     242 * @since 2.1.0
     243 * @since 5.0.0 Return value modified to indicate success or failure.
    232244 *
    233245 * @param string $hook Action hook, the execution of which will be unscheduled.
    234246 * @param array $args Optional. Arguments that were to be passed to the hook's callback function.
     247 * @return bool|int On success an integer indicating number of events unscheduled (0 indicates no
     248 *                  events were registered with the hook and arguments combination), false if
     249 *                  unscheduling one or more events fail.
    235250 */
    236251function wp_clear_scheduled_hook( $hook, $args = array() ) {
     
    247262    $crons = _get_cron_array();
    248263    if ( empty( $crons ) ) {
    249         return;
    250     }
    251 
    252     $key = md5( serialize( $args ) );
     264        return 0;
     265    }
     266
     267    $results = array();
     268    $key     = md5( serialize( $args ) );
    253269    foreach ( $crons as $timestamp => $cron ) {
    254270        if ( isset( $cron[ $hook ][ $key ] ) ) {
    255             wp_unschedule_event( $timestamp, $hook, $args );
    256         }
    257     }
     271            $results[] = wp_unschedule_event( $timestamp, $hook, $args );
     272        }
     273    }
     274    if ( in_array( false, $results, true ) ) {
     275        return false;
     276    }
     277    return count( $results );
    258278}
    259279
     
    263283 * Can be useful for plugins when deactivating to clean up the cron queue.
    264284 *
     285 * Warning: This function may return Boolean FALSE, but may also return a non-Boolean
     286 * value which evaluates to FALSE. For information about casting to booleans see the
     287 * {@link https://php.net/manual/en/language.types.boolean.php PHP documentation}. Use
     288 * the `===` operator for testing the return value of this function.
     289 *
    265290 * @since 4.9.0
     291 * @since 5.0.0 Return value added to indicate success or failure.
    266292 *
    267293 * @param string $hook Action hook, the execution of which will be unscheduled.
     294 * @return bool|int On success an integer indicating number of events unscheduled (0 indicates no
     295 *                  events were registered on the hook), false if unscheduling fails.
    268296 */
    269297function wp_unschedule_hook( $hook ) {
    270298    $crons = _get_cron_array();
    271 
     299    if ( empty( $crons ) ) {
     300        return 0;
     301    }
     302
     303    $results = array();
    272304    foreach ( $crons as $timestamp => $args ) {
     305        if ( ! empty( $crons[ $timestamp ][ $hook ] ) ) {
     306            $results[] = count( $crons[ $timestamp ][ $hook ] );
     307        }
    273308        unset( $crons[ $timestamp ][ $hook ] );
    274309
     
    278313    }
    279314
    280     _set_cron_array( $crons );
     315    /*
     316     * If the results are empty (zero events to unschedule), no attempt
     317     * to update the cron array is required.
     318     */
     319    if ( empty( $results ) ) {
     320        return 0;
     321    }
     322    if ( _set_cron_array( $crons ) ) {
     323        return array_sum( $results );
     324    }
     325    return false;
    281326}
    282327
     
    310355 *
    311356 * @since 2.1.0
     357 * @since 5.0.0 Return values added.
    312358 *
    313359 * @param int $gmt_time Optional. Unix timestamp (UTC). Default 0 (current time is used).
     360 * @return bool True if spawned, false if no events spawned.
    314361 */
    315362function spawn_cron( $gmt_time = 0 ) {
     
    319366
    320367    if ( defined( 'DOING_CRON' ) || isset( $_GET['doing_wp_cron'] ) ) {
    321         return;
     368        return false;
    322369    }
    323370
     
    337384    // don't run if another process is currently running it or more than once every 60 sec.
    338385    if ( $lock + WP_CRON_LOCK_TIMEOUT > $gmt_time ) {
    339         return;
     386        return false;
    340387    }
    341388
     
    343390    $crons = _get_cron_array();
    344391    if ( ! is_array( $crons ) ) {
    345         return;
     392        return false;
    346393    }
    347394
    348395    $keys = array_keys( $crons );
    349396    if ( isset( $keys[0] ) && $keys[0] > $gmt_time ) {
    350         return;
     397        return false;
    351398    }
    352399
    353400    if ( defined( 'ALTERNATE_WP_CRON' ) && ALTERNATE_WP_CRON ) {
    354401        if ( 'GET' !== $_SERVER['REQUEST_METHOD'] || defined( 'DOING_AJAX' ) || defined( 'XMLRPC_REQUEST' ) ) {
    355             return;
     402            return false;
    356403        }
    357404
     
    369416
    370417        WP_DEBUG ? include_once( ABSPATH . 'wp-cron.php' ) : @include_once( ABSPATH . 'wp-cron.php' );
    371         return;
     418        return true;
    372419    }
    373420
     
    410457    );
    411458
    412     wp_remote_post( $cron_request['url'], $cron_request['args'] );
     459    $result = wp_remote_post( $cron_request['url'], $cron_request['args'] );
     460    return ! is_wp_error( $result );
    413461}
    414462
     
    416464 * Run scheduled callbacks or spawn cron for all scheduled events.
    417465 *
    418  * @since 2.1.0
     466 * Warning: This function may return Boolean FALSE, but may also return a non-Boolean
     467 * value which evaluates to FALSE. For information about casting to booleans see the
     468 * {@link https://php.net/manual/en/language.types.boolean.php PHP documentation}. Use
     469 * the `===` operator for testing the return value of this function.
     470 *
     471 * @since 2.1.0
     472 * @since 5.0.0 Return value added to indicate success or failure.
     473 *
     474 * @return bool|int On success an integer indicating number of events spawned (0 indicates no
     475 *                  events needed to be spawned), false if spawning fails for one or more events.
    419476 */
    420477function wp_cron() {
    421478    // Prevent infinite loops caused by lack of wp-cron.php
    422479    if ( strpos( $_SERVER['REQUEST_URI'], '/wp-cron.php' ) !== false || ( defined( 'DISABLE_WP_CRON' ) && DISABLE_WP_CRON ) ) {
    423         return;
    424     }
    425 
    426     if ( false === $crons = _get_cron_array() ) {
    427         return;
     480        return 0;
     481    }
     482
     483    $crons = _get_cron_array();
     484    if ( false === $crons ) {
     485        return 0;
    428486    }
    429487
     
    431489    $keys     = array_keys( $crons );
    432490    if ( isset( $keys[0] ) && $keys[0] > $gmt_time ) {
    433         return;
     491        return 0;
    434492    }
    435493
    436494    $schedules = wp_get_schedules();
     495    $results   = array();
    437496    foreach ( $crons as $timestamp => $cronhooks ) {
    438497        if ( $timestamp > $gmt_time ) {
     
    443502                continue;
    444503            }
    445             spawn_cron( $gmt_time );
     504            $results[] = spawn_cron( $gmt_time );
    446505            break 2;
    447506        }
    448507    }
     508
     509    if ( in_array( false, $results, true ) ) {
     510        return false;
     511    }
     512    return count( $results );
    449513}
    450514
     
    559623 *
    560624 * @since 2.1.0
     625 * @since 5.0.0 Return value modified to outcome of {@see update_option}.
     626 *
    561627 * @access private
    562628 *
    563629 * @param array $cron Cron info array from _get_cron_array().
     630 * @return bool True if cron array updated, false on failure.
    564631 */
    565632function _set_cron_array( $cron ) {
    566633    $cron['version'] = 2;
    567     update_option( 'cron', $cron );
     634    return update_option( 'cron', $cron );
    568635}
    569636
  • trunk/tests/phpunit/tests/cron.php

    r42343 r43050  
    3030        $timestamp = strtotime( '+1 hour' );
    3131
    32         wp_schedule_single_event( $timestamp, $hook );
     32        $scheduled = wp_schedule_single_event( $timestamp, $hook );
     33        $this->assertTrue( $scheduled );
    3334        $this->assertEquals( $timestamp, wp_next_scheduled( $hook ) );
    3435
     
    4445        $args      = array( 'foo' );
    4546
    46         wp_schedule_single_event( $timestamp, $hook, $args );
     47        $scheduled = wp_schedule_single_event( $timestamp, $hook, $args );
     48        $this->assertTrue( $scheduled );
    4749        // this returns the timestamp only if we provide matching args
    4850        $this->assertEquals( $timestamp, wp_next_scheduled( $hook, $args ) );
     
    6163        $timestamp = strtotime( '+1 hour' );
    6264
    63         wp_schedule_event( $timestamp, $recur, $hook );
     65        $scheduled = wp_schedule_event( $timestamp, $recur, $hook );
     66        $this->assertTrue( $scheduled );
    6467        // it's scheduled for the right time
    6568        $this->assertEquals( $timestamp, wp_next_scheduled( $hook ) );
     
    7578        $args      = array( 'foo' );
    7679
    77         wp_schedule_event( $timestamp, 'hourly', $hook, $args );
     80        $scheduled = wp_schedule_event( $timestamp, 'hourly', $hook, $args );
     81        $this->assertTrue( $scheduled );
    7882        // this returns the timestamp only if we provide matching args
    7983        $this->assertEquals( $timestamp, wp_next_scheduled( $hook, $args ) );
     
    9599
    96100        // now unschedule it and make sure it's gone
    97         wp_unschedule_event( $timestamp, $hook );
     101        $unscheduled = wp_unschedule_event( $timestamp, $hook );
     102        $this->assertTrue( $unscheduled );
    98103        $this->assertEquals( false, wp_next_scheduled( $hook ) );
    99104    }
     
    114119
    115120        // clear the schedule for the no args events and make sure it's gone
    116         wp_clear_scheduled_hook( $hook );
     121        $hook_unscheduled = wp_clear_scheduled_hook( $hook );
     122        $this->assertSame( 2, $hook_unscheduled );
    117123        $this->assertFalse( wp_next_scheduled( $hook ) );
    118124        // the args events should still be there
     
    123129        wp_clear_scheduled_hook( $hook, $args );
    124130        $this->assertFalse( wp_next_scheduled( $hook, $args ) );
     131    }
     132
     133    function test_clear_undefined_schedule() {
     134        $hook = __FUNCTION__;
     135        $args = array( 'arg1' );
     136
     137        wp_schedule_single_event( strtotime( '+1 hour' ), $hook, $args );
     138        wp_schedule_single_event( strtotime( '+2 hour' ), $hook, $args );
     139
     140        // clear the schedule for no args events and ensure no events are cleared.
     141        $hook_unscheduled = wp_clear_scheduled_hook( $hook );
     142        $this->assertSame( 0, $hook_unscheduled );
    125143    }
    126144
     
    207225
    208226        // clear the schedule and make sure it's gone.
    209         wp_unschedule_hook( $hook );
     227        $unschedule_hook = wp_unschedule_hook( $hook );
     228        $this->assertSame( 4, $unschedule_hook );
     229        $this->assertFalse( wp_next_scheduled( $hook ) );
     230    }
     231
     232    function test_unschedule_undefined_hook() {
     233        $hook           = __FUNCTION__;
     234        $unrelated_hook = __FUNCTION__ . '_two';
     235
     236        // Attempt to clear schedule on non-existant hook.
     237        $unschedule_hook = wp_unschedule_hook( $hook );
     238        $this->assertSame( 0, $unschedule_hook );
     239        $this->assertFalse( wp_next_scheduled( $hook ) );
     240
     241        // Repeat tests with populated cron array.
     242        wp_schedule_single_event( strtotime( '+1 hour' ), $unrelated_hook );
     243        wp_schedule_single_event( strtotime( '+2 hour' ), $unrelated_hook );
     244
     245        $unschedule_hook = wp_unschedule_hook( $hook );
     246        $this->assertSame( 0, $unschedule_hook );
    210247        $this->assertFalse( wp_next_scheduled( $hook ) );
    211248    }
     
    222259
    223260        // first one works
    224         wp_schedule_single_event( $ts1, $hook, $args );
     261        $this->assertTrue( wp_schedule_single_event( $ts1, $hook, $args ) );
    225262        // second one is ignored
    226         wp_schedule_single_event( $ts2, $hook, $args );
     263        $this->assertFalse( wp_schedule_single_event( $ts2, $hook, $args ) );
    227264
    228265        // the next event should be at +5 minutes, not +3
     
    241278
    242279        // first one works
    243         wp_schedule_single_event( $ts1, $hook, $args );
     280        $this->assertTrue( wp_schedule_single_event( $ts1, $hook, $args ) );
    244281        // second works too
    245         wp_schedule_single_event( $ts2, $hook, $args );
     282        $this->assertTrue( wp_schedule_single_event( $ts2, $hook, $args ) );
    246283
    247284        // the next event should be at +3 minutes, even though that one was scheduled second
     
    260297
    261298        // first one works
    262         wp_schedule_single_event( $ts1, $hook, $args );
     299        $this->assertTrue( wp_schedule_single_event( $ts1, $hook, $args ) );
    263300        // second works too
    264         wp_schedule_single_event( $ts2, $hook, $args );
     301        $this->assertTrue( wp_schedule_single_event( $ts2, $hook, $args ) );
    265302
    266303        // the next event should be at +3 minutes
Note: See TracChangeset for help on using the changeset viewer.