<?php if ( ! class_exists( 'WP_Queue' ) ) { class WP_Queue { /** * @var string */ public $table; /** * @var string */ public $failed_table; /** * @var int */ public $release_time = 60; /** * WP_Queue constructor */ public function __construct() { global $wpdb; $this->table = $wpdb->prefix . 'queue'; $this->failed_table = $wpdb->prefix . 'failed_jobs'; } /** * Push a job onto the queue. * * @param WP_Job $job * @param int $delay * * @return $this */ public function push( WP_Job $job, $delay = 0 ) { global $wpdb; $data = array( 'job' => maybe_serialize( $job ), 'available_at' => $this->datetime( $delay ), 'created_at' => $this->datetime(), ); $id = $wpdb->insert( $this->table, $data ); if (!$id) { try { if (mailchimp_string_contains($wpdb->last_error, 'Table')) { mailchimp_debug('Queue Table Was Not Found!', 'Creating Tables'); MailChimp_WooCommerce_Activator::create_queue_tables(); $id = $wpdb->insert( $this->table, $data ); if (!$id) { mailchimp_debug('Queue Job '.get_class($job), $wpdb->last_error); } } } catch (\Exception $e) { mailchimp_error_trace($e, 'trying to create queue tables'); } } return $this; } /** * Release. * * @param object $job * @param int $delay */ public function release( $job, $delay = 0 ) { if ( $job->attempts >= 3 ) { $this->failed( $job ); return; } global $wpdb; $data = array( 'attempts' => $job->attempts + 1, 'locked' => 0, 'locked_at' => null, 'available_at' => $this->datetime( $delay ), ); $where = array( 'id' => $job->id, ); $wpdb->update( $this->table, $data, $where ); } /** * Failed * * @param stdClass $job */ protected function failed( $job ) { global $wpdb; $wpdb->insert( $this->failed_table, array( 'job' => $job->job, 'failed_at' => $this->datetime(), ) ); $payload = unserialize($job->job); if (method_exists($payload, 'failed')) { $payload->failed(); } $this->delete( $job ); } /** * Delete. * * @param object $job */ public function delete( $job ) { global $wpdb; $wpdb->delete($this->table, array('id' => $job->id)); } /** * Get MySQL datetime. * * @param int $offset Seconds, can pass negative int. * * @return string */ protected function datetime($offset = 0) { $timestamp = time() + $offset; return gmdate( 'Y-m-d H:i:s', $timestamp ); } /** * Available jobs. */ public function available_jobs() { global $wpdb; $now = $this->datetime(); $sql = $wpdb->prepare( " SELECT COUNT(*) FROM {$this->table} WHERE available_at <= %s" , $now ); return $wpdb->get_var( $sql ); } /** * Available jobs. */ public function failed_jobs() { global $wpdb; return $wpdb->get_var( "SELECT COUNT(*) FROM {$this->failed_table}" ); } /** * Restart failed jobs. */ public function restart_failed_jobs() { global $wpdb; $count = 0; $jobs = $wpdb->get_results( "SELECT * FROM {$this->failed_table}" ); foreach ( $jobs as $job ) { $this->push( maybe_unserialize( $job->job ) ); $wpdb->delete( $this->failed_table, array( 'id' => $job->id, ) ); $count++; } return $count; } /** * Get next job. */ public function get_next_job() { global $wpdb; $this->maybe_release_locked_jobs(); $now = $this->datetime(); $sql = $wpdb->prepare( " SELECT * FROM {$this->table} WHERE locked = 0 AND available_at <= %s" , $now ); return $wpdb->get_row( $sql ); } /** * Maybe release locked jobs. */ protected function maybe_release_locked_jobs() { global $wpdb; $expired = $this->datetime( - $this->release_time ); $sql = $wpdb->prepare( " UPDATE {$this->table} SET attempts = attempts + 1, locked = 0, locked_at = NULL WHERE locked = 1 AND locked_at <= %s" , $expired ); $wpdb->query( $sql ); } /** * Lock job. * * @param object $job */ public function lock_job( $job ) { global $wpdb; $data = array( 'locked' => 1, 'locked_at' => $this->datetime(), ); $where = array( 'id' => $job->id, ); $wpdb->update( $this->table, $data, $where ); } } }