dispatcher = $dispatcher; $this->poller = $poller; $this->results = $results; } public function register_hooks(): void { add_action( self::CRON_HOOK, array( $this, 'dispatch' ), 10, 2 ); } public function schedule( ReleaseEvent $event ): void { $key = $event->debounce_key(); if ( $event->is_automatic() && false !== get_transient( $key ) ) { return; } $scheduled = wp_schedule_single_event( time() + 5, self::CRON_HOOK, array( $event->to_payload(), 0 ) ); if ( true === $scheduled && $event->is_automatic() ) { set_transient( $key, '1', self::DEBOUNCE_SECONDS ); } } /** @param array $payload WordPress Cron boundary payload. */ public function dispatch( array $payload, int $attempt = 0 ): void { $event = ReleaseEvent::from_payload( $payload ); if ( ! $event instanceof ReleaseEvent ) { return; } try { $summary = $this->dispatcher->dispatch( $event ); if ( $summary instanceof RunSummary ) { $this->poller->start( $summary ); } } catch ( ApiException $exception ) { $this->results->mark_error( $exception->error_code() ); if ( 0 === $attempt && $this->retryable( $exception ) ) { wp_schedule_single_event( time() + self::RETRY_SECONDS, self::CRON_HOOK, array( $payload, 1 ) ); } } } private function retryable( ApiException $exception ): bool { return in_array( $exception->error_code(), array( ApiException::QUEUE, ApiException::REMOTE_FETCH ), true ); } }