Make WordPress Core

Changeset 44693


Ignore:
Timestamp:
01/23/2019 11:07:39 PM (6 years ago)
Author:
peterwilsoncc
Message:

Cron: Move logic for finding the next event's timestamp.

Moves the logic for determining when an event will next run from wp_next_scheduled() to wp_get_scheduled_event().

This improves the performance of wp_get_scheduled_event() by avoiding duplicate function calls and object cache hits.

Props peterwilsoncc.
Fixes #45976.

Location:
trunk
Files:
2 edited

Legend:

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

    r44483 r44693  
    482482 * Retrieve a scheduled event.
    483483 *
    484  * Retrieve the full event object for a given event.
     484 * Retrieve the full event object for a given event, if no timestamp is specified the next
     485 * scheduled event is returned.
    485486 *
    486487 * @since 5.1.0
     
    494495 */
    495496function wp_get_scheduled_event( $hook, $args = array(), $timestamp = null ) {
    496     if ( ! $timestamp ) {
    497         // Get the next scheduled event.
    498         $timestamp = wp_next_scheduled( $hook, $args );
    499     }
    500 
    501497    /**
    502498     * Filter to preflight or hijack retrieving a scheduled event.
     
    515511     *                             Although not passed to a callback, these arguments are used to uniquely identify the
    516512     *                             event.
    517      * @param int       $timestamp Unix timestamp (UTC) of the event.
     513     * @param int|null  $timestamp Unix timestamp (UTC) of the event. Null to retrieve next scheduled event.
    518514     */
    519515    $pre = apply_filters( 'pre_get_scheduled_event', null, $hook, $args, $timestamp );
     
    522518    }
    523519
     520    if ( null !== $timestamp && ! is_numeric( $timestamp ) ) {
     521        return false;
     522    }
     523
    524524    $crons = _get_cron_array();
    525     $key   = md5( serialize( $args ) );
    526 
    527     if ( ! $timestamp || ! isset( $crons[ $timestamp ] ) ) {
    528         // No such event.
    529         return false;
    530     }
    531 
    532     if ( ! isset( $crons[ $timestamp ][ $hook ] ) || ! isset( $crons[ $timestamp ][ $hook ][ $key ] ) ) {
     525    if ( empty( $crons ) ) {
     526        return false;
     527    }
     528
     529    $key = md5( serialize( $args ) );
     530
     531    if ( ! $timestamp ) {
     532        // Get next event.
     533        $next = false;
     534        foreach ( $crons as $timestamp => $cron ) {
     535            if ( isset( $cron[ $hook ][ $key ] ) ) {
     536                $next = $timestamp;
     537                break;
     538            }
     539        }
     540        if ( ! $next ) {
     541            return false;
     542        }
     543
     544        $timestamp = $next;
     545    } elseif ( ! isset( $crons[ $timestamp ][ $hook ][ $key ] ) ) {
    533546        return false;
    534547    }
     
    552565 *
    553566 * @since 2.1.0
    554  * @since 5.1.0 {@see 'pre_next_scheduled'} and {@see 'next_scheduled'} filters added.
    555567 *
    556568 * @param string $hook Action hook of the event.
     
    561573 */
    562574function wp_next_scheduled( $hook, $args = array() ) {
    563     /**
    564      * Filter to preflight or hijack retrieving the next scheduled event timestamp.
    565      *
    566      * Returning a non-null value will short-circuit the normal retrieval
    567      * process, causing the function to return the filtered value instead.
    568      *
    569      * Pass the timestamp of the next event if it exists, false if not.
    570      *
    571      * @since 5.1.0
    572      *
    573      * @param null|bool $pre       Value to return instead. Default null to continue unscheduling the event.
    574      * @param string    $hook      Action hook of the event.
    575      * @param array     $args      Arguments to pass to the hook's callback function.
    576      */
    577     $pre = apply_filters( 'pre_next_scheduled', null, $hook, $args );
    578     if ( null !== $pre ) {
    579         return $pre;
    580     }
    581 
    582     $crons = _get_cron_array();
    583     $key   = md5( serialize( $args ) );
    584     $next  = false;
    585 
    586     if ( ! empty( $crons ) ) {
    587         foreach ( $crons as $timestamp => $cron ) {
    588             if ( isset( $cron[ $hook ][ $key ] ) ) {
    589                 $next = $timestamp;
    590                 break;
    591             }
    592         }
    593     }
    594 
    595     /**
    596      * Filter the next scheduled event timestamp.
    597      *
    598      * @since 5.1.0
    599      *
    600      * @param int|bool $next The UNIX timestamp when the scheduled event will next occur, or false if not found.
    601      * @param string   $hook Action hook to execute when cron is run.
    602      * @param array    $args Arguments to be passed to the callback function. Used for deduplicating events.
    603      */
    604     return apply_filters( 'next_scheduled', $next, $hook, $args );
     575    $next_event = wp_get_scheduled_event( $hook, $args );
     576    if ( ! $next_event ) {
     577        return false;
     578    }
     579
     580    return $next_event->timestamp;
    605581}
    606582
  • trunk/tests/phpunit/tests/cron.php

    r43571 r44693  
    459459    function test_pre_scheduled_event_hooks() {
    460460        add_filter( 'pre_get_scheduled_event', array( $this, 'filter_pre_scheduled_event_hooks' ) );
    461         add_filter( 'pre_next_scheduled', array( $this, 'filter_pre_scheduled_event_hooks' ) );
    462461
    463462        $actual  = wp_get_scheduled_event( 'preflight_event', array(), $this->plus_thirty_minutes );
     
    472471
    473472        $this->assertEquals( $expected, $actual );
    474         $this->assertEquals( $expected, $actual2 );
     473        $this->assertEquals( $expected->timestamp, $actual2 );
    475474    }
    476475
     
    483482        );
    484483    }
     484
     485    /**
     486     * Ensure wp_get_scheduled_event() returns the expected one off events.
     487     *
     488     * When no timestamp is specified, the next event should be returned.
     489     * When a timestamp is specified, a particular event should be returned.
     490     *
     491     * @ticket 45976.
     492     */
     493    function test_get_scheduled_event_singles() {
     494        $hook    = __FUNCTION__;
     495        $args    = array( 'arg1' );
     496        $ts_late = strtotime( '+30 minutes' );
     497        $ts_next = strtotime( '+3 minutes' );
     498
     499        $expected1 = (object) array(
     500            'hook'      => $hook,
     501            'timestamp' => $ts_late,
     502            'schedule'  => false,
     503            'args'      => $args,
     504        );
     505
     506        $expected2 = (object) array(
     507            'hook'      => $hook,
     508            'timestamp' => $ts_next,
     509            'schedule'  => false,
     510            'args'      => $args,
     511        );
     512
     513        // Schedule late running event.
     514        wp_schedule_single_event( $ts_late, $hook, $args );
     515        // Schedule next running event.
     516        wp_schedule_single_event( $ts_next, $hook, $args );
     517
     518        // Late running, timestamp specified.
     519        $this->assertEquals( $expected1, wp_get_scheduled_event( $hook, $args, $ts_late ) );
     520
     521        // Next running, timestamp specified.
     522        $this->assertEquals( $expected2, wp_get_scheduled_event( $hook, $args, $ts_next ) );
     523
     524        // Next running, no timestamp specified.
     525        $this->assertEquals( $expected2, wp_get_scheduled_event( $hook, $args ) );
     526    }
     527
     528    /**
     529     * Ensure wp_get_scheduled_event() returns the expected recurring events.
     530     *
     531     * When no timestamp is specified, the next event should be returned.
     532     * When a timestamp is specified, a particular event should be returned.
     533     *
     534     * @ticket 45976.
     535     */
     536    function test_get_scheduled_event_recurring() {
     537        $hook     = __FUNCTION__;
     538        $args     = array( 'arg1' );
     539        $ts_late  = strtotime( '+30 minutes' );
     540        $ts_next  = strtotime( '+3 minutes' );
     541        $schedule = 'hourly';
     542        $interval = HOUR_IN_SECONDS;
     543
     544        $expected1 = (object) array(
     545            'hook'      => $hook,
     546            'timestamp' => $ts_late,
     547            'schedule'  => $schedule,
     548            'args'      => $args,
     549            'interval'  => $interval,
     550        );
     551
     552        $expected2 = (object) array(
     553            'hook'      => $hook,
     554            'timestamp' => $ts_next,
     555            'schedule'  => $schedule,
     556            'args'      => $args,
     557            'interval'  => $interval,
     558        );
     559
     560        // Schedule late running event.
     561        wp_schedule_event( $ts_late, $schedule, $hook, $args );
     562        // Schedule next running event.
     563        wp_schedule_event( $ts_next, $schedule, $hook, $args );
     564
     565        // Late running, timestamp specified.
     566        $this->assertEquals( $expected1, wp_get_scheduled_event( $hook, $args, $ts_late ) );
     567
     568        // Next running, timestamp specified.
     569        $this->assertEquals( $expected2, wp_get_scheduled_event( $hook, $args, $ts_next ) );
     570
     571        // Next running, no timestamp specified.
     572        $this->assertEquals( $expected2, wp_get_scheduled_event( $hook, $args ) );
     573    }
     574
     575    /**
     576     * Ensure wp_get_scheduled_event() returns false when expected.
     577     *
     578     * @ticket 45976.
     579     */
     580    function test_get_scheduled_event_false() {
     581        $hook = __FUNCTION__;
     582        $args = array( 'arg1' );
     583        $ts   = strtotime( '+3 minutes' );
     584
     585        // No scheduled events.
     586        // - With timestamp
     587        $this->assertFalse( wp_get_scheduled_event( $hook, $args, $ts ) );
     588        // - Get next, none scheduled.
     589        $this->assertFalse( wp_get_scheduled_event( $hook, $args ) );
     590
     591        // Schedule an event.
     592        wp_schedule_event( $ts, $hook, $args );
     593        // - unregistered timestamp
     594        $this->assertFalse( wp_get_scheduled_event( $hook, $args, strtotime( '+30 minutes' ) ) );
     595        // - invalid timestamp.
     596        $this->assertFalse( wp_get_scheduled_event( $hook, $args, 'Words Fail!' ) );
     597
     598    }
    485599}
Note: See TracChangeset for help on using the changeset viewer.