From c36fef1d5026bb075a58f962861b5a978c5e99bb Mon Sep 17 00:00:00 2001 From: Chris Huber Date: Wed, 6 May 2026 17:25:35 -0400 Subject: [PATCH] fix: guard scheduler checks before AS datastore init --- data-machine.php | 17 +++++ inc/Core/Admin/FlowFormatter.php | 21 ++++++ inc/Engine/Tasks/RecurringScheduler.php | 26 ++++++++ ...recurring-scheduler-as-readiness-smoke.php | 65 +++++++++++++++++++ 4 files changed, 129 insertions(+) create mode 100644 tests/recurring-scheduler-as-readiness-smoke.php diff --git a/data-machine.php b/data-machine.php index 0d49640d1..545ce2b78 100644 --- a/data-machine.php +++ b/data-machine.php @@ -48,6 +48,23 @@ require_once __DIR__ . '/vendor/woocommerce/action-scheduler/action-scheduler.php'; } +if ( function_exists( 'wp_installing' ) && wp_installing() ) { + add_action( 'wp_loaded', 'datamachine_skip_action_scheduler_migration_during_install', 0 ); +} + +/** + * Prevent AS migration scheduling during wp-phpunit install bootstrap. + * + * @return void + */ +function datamachine_skip_action_scheduler_migration_during_install(): void { + if ( ! class_exists( '\Action_Scheduler\Migration\Controller' ) ) { + return; + } + + remove_action( 'wp_loaded', array( \Action_Scheduler\Migration\Controller::instance(), 'schedule_migration' ) ); +} + function datamachine_run_datamachine_plugin() { if ( ! datamachine_should_load_full_runtime() ) { diff --git a/inc/Core/Admin/FlowFormatter.php b/inc/Core/Admin/FlowFormatter.php index 809e5ae4b..1f5c5e143 100644 --- a/inc/Core/Admin/FlowFormatter.php +++ b/inc/Core/Admin/FlowFormatter.php @@ -135,11 +135,32 @@ private static function get_next_run_time( ?int $flow_id ): ?string { return null; } + if ( ! self::is_action_scheduler_datastore_ready() ) { + return null; + } + $next_timestamp = as_next_scheduled_action( 'datamachine_run_flow_now', array( $flow_id ), 'data-machine' ); return $next_timestamp ? wp_date( 'Y-m-d H:i:s', $next_timestamp, new \DateTimeZone( 'UTC' ) ) : null; } + /** + * Check whether Action Scheduler's datastore is ready for procedural API reads. + * + * @return bool True when Action Scheduler can safely query scheduled actions. + */ + private static function is_action_scheduler_datastore_ready(): bool { + if ( function_exists( 'did_action' ) && 0 === did_action( 'action_scheduler_init' ) ) { + return false; + } + + if ( ! class_exists( '\ActionScheduler' ) || ! method_exists( '\ActionScheduler', 'is_initialized' ) ) { + return true; + } + + return \ActionScheduler::is_initialized(); + } + /** * Batch-fetch next run times for multiple flows in a single query. * diff --git a/inc/Engine/Tasks/RecurringScheduler.php b/inc/Engine/Tasks/RecurringScheduler.php index c56fb3fe5..353fb26b2 100644 --- a/inc/Engine/Tasks/RecurringScheduler.php +++ b/inc/Engine/Tasks/RecurringScheduler.php @@ -262,9 +262,31 @@ public static function isScheduled( string $hook, array $args, string $group = s if ( ! function_exists( 'as_next_scheduled_action' ) ) { return false; } + + if ( ! self::isActionSchedulerDataStoreReady() ) { + return false; + } + return false !== as_next_scheduled_action( $hook, $args, $group ); } + /** + * Check whether Action Scheduler's datastore is ready for procedural API reads. + * + * @return bool True when Action Scheduler can safely query scheduled actions. + */ + private static function isActionSchedulerDataStoreReady(): bool { + if ( function_exists( 'did_action' ) && 0 === did_action( 'action_scheduler_init' ) ) { + return false; + } + + if ( ! class_exists( '\ActionScheduler' ) || ! method_exists( '\ActionScheduler', 'is_initialized' ) ) { + return true; + } + + return \ActionScheduler::is_initialized(); + } + /** * Create a WP_Error with optional data without tripping scoped PHPStan stubs. * @@ -291,6 +313,10 @@ private static function getPendingAction( string $hook, array $args, string $gro return null; } + if ( ! self::isActionSchedulerDataStoreReady() ) { + return null; + } + $actions = as_get_scheduled_actions( array( 'hook' => $hook, diff --git a/tests/recurring-scheduler-as-readiness-smoke.php b/tests/recurring-scheduler-as-readiness-smoke.php new file mode 100644 index 000000000..8f2712ed6 --- /dev/null +++ b/tests/recurring-scheduler-as-readiness-smoke.php @@ -0,0 +1,65 @@ +