900, // 15 minutes in seconds (literal for phpcs/scanners). 'display' => Messages::format( 'cron.interval_display', self::INTERVAL_MIN ), ); } return $schedules; } /** * Schedule the event if missing. */ public static function maybe_schedule(): void { if ( ! wp_next_scheduled( self::EVENT_HOOK ) ) { wp_schedule_event( time() + self::SCHEDULE_OFFSET_SECONDS, self::INTERVAL_KEY, self::EVENT_HOOK ); } } /** * Activation hook to ensure cron is scheduled. */ public static function activate(): void { self::maybe_schedule(); } /** * Deactivation hook to clear scheduled events and locks. */ public static function deactivate(): void { // Clear all future instances of this hook. $timestamp = wp_next_scheduled( self::EVENT_HOOK ); while ( $timestamp ) { wp_unschedule_event( $timestamp, self::EVENT_HOOK ); $timestamp = wp_next_scheduled( self::EVENT_HOOK ); } // Drop lock if set. PollRunner::release_lock( self::lock_key() ); } /** * Cron callback that pulls pending batch requests while avoiding overlaps. */ public static function run(): void { $lock_key = self::lock_key(); $ttl_seconds = (int) max( 60, min( self::INTERVAL_SECONDS - 30, 3600 ) ); $acquired = PollRunner::run_with_lock( $lock_key, $ttl_seconds, function () { if ( ! BatchRequest::has_incomplete_batch_requests() ) { Logger::write_log( 'info', '[CRON] No incomplete batch requests. Skipping pull_all.' ); return; } Logger::write_log( 'info', '[CRON] Incomplete batch requests found. Running pull_all().' ); BatchRequest::pull_all(); }, '[CRON] pull_all' ); if ( ! $acquired ) { Logger::write_log( 'info', '[CRON] pull_all skipped: lock present.' ); } } /** * Get the lock transient key. * * @return string */ protected static function lock_key(): string { return 'ai_content_by_parallax_pull_all_lock'; } }