Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Significance: minor
Type: changed

Ensure we sync directly during cron.
9 changes: 7 additions & 2 deletions projects/packages/sync/src/class-sender.php
Original file line number Diff line number Diff line change
Expand Up @@ -358,7 +358,10 @@ private function continue_full_sync_enqueue() {
* @return boolean|WP_Error True if this sync sending was successful, error object otherwise.
*/
public function do_sync() {
if ( ! Settings::is_dedicated_sync_enabled() ) {
// Sync directly during cron. We are doing this because otherwise
// the dedicated sync flow would be spawning HTTP requests during cron shutdown,
// which can be unreliable and cause sync lag for time-sensitive events like updates.
if ( ! Settings::is_dedicated_sync_enabled() || Settings::is_doing_cron() ) {
$result = $this->do_sync_and_set_delays( $this->sync_queue );
} else {
$result = Dedicated_Sender::spawn_sync( $this->sync_queue );
Expand Down Expand Up @@ -498,7 +501,9 @@ public function do_sync_and_set_delays( $queue ) {
$this->set_next_sync_time( time() + self::WPCOM_ERROR_SYNC_DELAY, $queue->id );
}
} elseif ( $exceeded_sync_wait_threshold && ! Settings::is_doing_cron() ) {
// If we actually sent data and it took a while, wait before sending again.
// If a send was slow, briefly pause before the next one.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While considering the new direct sync flow via cron, it made sense to update this comment to give a little more clarity around why cron jobs are exempt (since the intention is to minimize Sync's impact on actual user requests, which only makes sense for dedicated and normal sync flows).

// Applies only to Dedicated/Normal Sync to avoid impacting user traffic;
// cron jobs are exempt.
$this->set_next_sync_time( time() + $this->get_sync_wait_time(), $queue->id );
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Significance: patch
Type: other
Comment: Tests: Updating sync tests to consider that we now allow syncing directly during cron.


Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ public function tear_down() {
// Restore default setting.
Settings::update_settings( array( 'dedicated_sync_enabled' => 0 ) );

// Reset cron flag to default behavior.
Settings::set_doing_cron( null );

delete_transient( Dedicated_Sender::DEDICATED_SYNC_CHECK_TRANSIENT );

// Reset queue.
Expand Down Expand Up @@ -624,6 +627,85 @@ public function test_do_sync_errors_if_read_only() {
$this->assertTrue( is_wp_error( $response ) );
}

/**
* Test do_sync syncs directly when doing cron even if dedicated sync is enabled.
*/
public function test_do_sync_runs_inline_when_doing_cron_even_if_dedicated_enabled() {
Settings::update_settings( array( 'dedicated_sync_enabled' => 1 ) );
Settings::set_doing_cron( true );
self::factory()->post->create();

add_filter( 'pre_http_request', array( $this, 'pre_http_sync_request_spawned' ), 10, 3 );
$this->sender->do_sync();
remove_filter( 'pre_http_request', array( $this, 'pre_http_sync_request_spawned' ) );
Settings::set_doing_cron( null );

$this->assertFalse( $this->dedicated_sync_request_spawned );

$event = $this->server_event_storage->get_most_recent_event( 'jetpack_sync_save_post' );
$this->assertNotNull( $event );
}

/**
* Test do_sync syncs directly when doing cron even with an active dedicated sync lock.
*/
public function test_do_sync_runs_inline_when_doing_cron_even_with_dedicated_lock_set() {
Settings::update_settings( array( 'dedicated_sync_enabled' => 1 ) );
Settings::set_doing_cron( true );

// Set up an active dedicated sync lock.
$lock_option_name = Dedicated_Sender::DEDICATED_SYNC_REQUEST_LOCK_OPTION_NAME;
\Jetpack_Options::update_raw_option( $lock_option_name, 'dummy' );
$lock_expires_name = $lock_option_name . '_expires';
$expires_at = microtime( true ) + 10;
\Jetpack_Options::update_raw_option( $lock_expires_name, $expires_at );

self::factory()->post->create();

add_filter( 'pre_http_request', array( $this, 'pre_http_sync_request_spawned' ), 10, 3 );
$this->sender->do_sync();
remove_filter( 'pre_http_request', array( $this, 'pre_http_sync_request_spawned' ) );
Settings::set_doing_cron( null );

$this->assertFalse( $this->dedicated_sync_request_spawned );

$event = $this->server_event_storage->get_most_recent_event( 'jetpack_sync_save_post' );
$this->assertNotNull( $event );
}

/**
* Test do_sync does not set throttle when doing cron.
*/
public function test_do_sync_does_not_set_throttle_when_doing_cron() {
// Flush any existing queue items first.
$this->sender->do_sync();

Settings::set_doing_cron( true );

// Set up throttling config.
$this->sender->set_upload_max_rows( 2 );
$this->sender->set_sync_wait_time( 2 );
$this->sender->set_sync_wait_threshold( 0 );

add_action( 'demo_action', array( $this->listener, 'action_handler' ) );

do_action( 'demo_action' );
do_action( 'demo_action' );
do_action( 'demo_action' );
do_action( 'demo_action' );

// First sync should work and send 2 items.
$this->assertTrue( $this->sender->do_sync() );
$this->assertCount( 2, $this->server_event_storage->get_all_events( 'demo_action' ) );

// Second sync should also work (not throttled) because cron doesn't set throttles.
$result = $this->sender->do_sync();
$this->assertTrue( $result );
$this->assertCount( 4, $this->server_event_storage->get_all_events( 'demo_action' ) );
Settings::set_doing_cron( null );
remove_action( 'demo_action', array( $this->listener, 'action_handler' ) );
}

/**
* Validate that WP_Error is returned in do_full_sync if JETPACK_SYNC_READ_ONLY is defined and true.
*/
Expand Down
Loading