transport = $transport; $this->queue = $queue; $this->policy = $policy; $this->logger = $logger; } /** * Deliver one job. * * @param Job $job Job to deliver. * @return bool Whether the collector accepted it. */ public function deliver( Job $job ): bool { $response = $this->transport->send( $job->endpoint(), $job->payload() ); if ( $response->is_ok() ) { return true; } $attempted = $job->next_attempt(); if ( ! $response->is_retryable() ) { // The collector understood the request and said no. Sending it again changes nothing, so // the job ends here and the reason is recorded where the site owner can find it. $this->logger->error( 'Delivery rejected, not retrying', array( 'job' => $job->describe(), 'status' => $response->status(), 'message' => $response->error(), ) ); return false; } if ( ! $this->policy->should_retry( $attempted->attempts() ) ) { $this->logger->error( 'Delivery abandoned after the final attempt', array( 'job' => $job->describe(), 'attempts' => $attempted->attempts(), 'message' => $response->error(), ) ); return false; } $delay = $this->policy->delay_for( $attempted->attempts() ); if ( ! $this->queue->retry( $attempted, $delay ) ) { $this->logger->error( 'Delivery lost: the queue would not accept a retry', array( 'job' => $job->describe() ) ); return false; } $this->logger->debug( 'Delivery deferred', array( 'job' => $job->describe(), 'attempts' => $attempted->attempts(), 'retry_in' => $delay, ) ); return false; } /** * Action Scheduler callback. * * @param mixed $raw Stored job array. * @return void */ public function handle_action( $raw = null ): void { $job = Job::from_array( $raw ); if ( null === $job ) { // Written by a version that stored a different shape, or truncated in the database. There is // nothing to deliver and nothing to retry. $this->logger->error( 'Discarded an unreadable queued job' ); return; } $this->deliver( $job ); } /** * Cron callback for the option-backed queue. * * @return void */ public function drain(): void { if ( ! $this->queue instanceof DrainableInterface ) { return; // Action Scheduler runs its own jobs; there is nothing here to pull. } foreach ( $this->queue->claim( self::BATCH ) as $job ) { $this->deliver( $job ); } } }