2019-03-28 05:31:13 +00:00
|
|
|
<?php
|
|
|
|
|
|
|
|
/**
|
|
|
|
* WP CLI Queue runner.
|
|
|
|
*
|
|
|
|
* This class can only be called from within a WP CLI instance.
|
|
|
|
*/
|
|
|
|
class ActionScheduler_WPCLI_QueueRunner extends ActionScheduler_Abstract_QueueRunner {
|
|
|
|
|
|
|
|
/** @var array */
|
|
|
|
protected $actions;
|
|
|
|
|
|
|
|
/** @var ActionScheduler_ActionClaim */
|
|
|
|
protected $claim;
|
|
|
|
|
|
|
|
/** @var \cli\progress\Bar */
|
|
|
|
protected $progress_bar;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* ActionScheduler_WPCLI_QueueRunner constructor.
|
|
|
|
*
|
|
|
|
* @param ActionScheduler_Store $store
|
|
|
|
* @param ActionScheduler_FatalErrorMonitor $monitor
|
|
|
|
* @param ActionScheduler_QueueCleaner $cleaner
|
|
|
|
*
|
|
|
|
* @throws Exception When this is not run within WP CLI
|
|
|
|
*/
|
|
|
|
public function __construct( ActionScheduler_Store $store = null, ActionScheduler_FatalErrorMonitor $monitor = null, ActionScheduler_QueueCleaner $cleaner = null ) {
|
|
|
|
if ( ! ( defined( 'WP_CLI' ) && WP_CLI ) ) {
|
|
|
|
/* translators: %s php class name */
|
2019-12-02 21:38:21 +00:00
|
|
|
throw new Exception( sprintf( __( 'The %s class can only be run within WP CLI.', 'woocommerce' ), __CLASS__ ) );
|
2019-03-28 05:31:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
parent::__construct( $store, $monitor, $cleaner );
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Set up the Queue before processing.
|
|
|
|
*
|
|
|
|
* @author Jeremy Pry
|
|
|
|
*
|
|
|
|
* @param int $batch_size The batch size to process.
|
|
|
|
* @param array $hooks The hooks being used to filter the actions claimed in this batch.
|
|
|
|
* @param string $group The group of actions to claim with this batch.
|
|
|
|
* @param bool $force Whether to force running even with too many concurrent processes.
|
|
|
|
*
|
|
|
|
* @return int The number of actions that will be run.
|
|
|
|
* @throws \WP_CLI\ExitException When there are too many concurrent batches.
|
|
|
|
*/
|
|
|
|
public function setup( $batch_size, $hooks = array(), $group = '', $force = false ) {
|
|
|
|
$this->run_cleanup();
|
|
|
|
$this->add_hooks();
|
|
|
|
|
|
|
|
// Check to make sure there aren't too many concurrent processes running.
|
|
|
|
$claim_count = $this->store->get_claim_count();
|
|
|
|
$too_many = $claim_count >= $this->get_allowed_concurrent_batches();
|
|
|
|
if ( $too_many ) {
|
|
|
|
if ( $force ) {
|
2019-12-02 21:38:21 +00:00
|
|
|
WP_CLI::warning( __( 'There are too many concurrent batches, but the run is forced to continue.', 'woocommerce' ) );
|
2019-03-28 05:31:13 +00:00
|
|
|
} else {
|
2019-12-02 21:38:21 +00:00
|
|
|
WP_CLI::error( __( 'There are too many concurrent batches.', 'woocommerce' ) );
|
2019-03-28 05:31:13 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Stake a claim and store it.
|
|
|
|
$this->claim = $this->store->stake_claim( $batch_size, null, $hooks, $group );
|
|
|
|
$this->monitor->attach( $this->claim );
|
|
|
|
$this->actions = $this->claim->get_actions();
|
|
|
|
|
|
|
|
return count( $this->actions );
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Add our hooks to the appropriate actions.
|
|
|
|
*
|
|
|
|
* @author Jeremy Pry
|
|
|
|
*/
|
|
|
|
protected function add_hooks() {
|
|
|
|
add_action( 'action_scheduler_before_execute', array( $this, 'before_execute' ) );
|
|
|
|
add_action( 'action_scheduler_after_execute', array( $this, 'after_execute' ), 10, 2 );
|
|
|
|
add_action( 'action_scheduler_failed_execution', array( $this, 'action_failed' ), 10, 2 );
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Set up the WP CLI progress bar.
|
|
|
|
*
|
|
|
|
* @author Jeremy Pry
|
|
|
|
*/
|
|
|
|
protected function setup_progress_bar() {
|
|
|
|
$count = count( $this->actions );
|
|
|
|
$this->progress_bar = \WP_CLI\Utils\make_progress_bar(
|
2019-12-02 21:38:21 +00:00
|
|
|
sprintf( _n( 'Running %d action', 'Running %d actions', $count, 'woocommerce' ), number_format_i18n( $count ) ),
|
2019-03-28 05:31:13 +00:00
|
|
|
$count
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Process actions in the queue.
|
|
|
|
*
|
|
|
|
* @author Jeremy Pry
|
|
|
|
* @return int The number of actions processed.
|
|
|
|
*/
|
|
|
|
public function run() {
|
|
|
|
do_action( 'action_scheduler_before_process_queue' );
|
|
|
|
$this->setup_progress_bar();
|
|
|
|
foreach ( $this->actions as $action_id ) {
|
|
|
|
// Error if we lost the claim.
|
|
|
|
if ( ! in_array( $action_id, $this->store->find_actions_by_claim_id( $this->claim->get_id() ) ) ) {
|
2019-12-02 21:38:21 +00:00
|
|
|
WP_CLI::warning( __( 'The claim has been lost. Aborting current batch.', 'woocommerce' ) );
|
2019-03-28 05:31:13 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
$this->process_action( $action_id );
|
|
|
|
$this->progress_bar->tick();
|
|
|
|
$this->maybe_stop_the_insanity();
|
|
|
|
}
|
|
|
|
|
|
|
|
$completed = $this->progress_bar->current();
|
|
|
|
$this->progress_bar->finish();
|
|
|
|
$this->store->release_claim( $this->claim );
|
|
|
|
do_action( 'action_scheduler_after_process_queue' );
|
|
|
|
|
|
|
|
return $completed;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Handle WP CLI message when the action is starting.
|
|
|
|
*
|
|
|
|
* @author Jeremy Pry
|
|
|
|
*
|
|
|
|
* @param $action_id
|
|
|
|
*/
|
|
|
|
public function before_execute( $action_id ) {
|
|
|
|
/* translators: %s refers to the action ID */
|
2019-12-02 21:38:21 +00:00
|
|
|
WP_CLI::log( sprintf( __( 'Started processing action %s', 'woocommerce' ), $action_id ) );
|
2019-03-28 05:31:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Handle WP CLI message when the action has completed.
|
|
|
|
*
|
|
|
|
* @author Jeremy Pry
|
|
|
|
*
|
|
|
|
* @param int $action_id
|
|
|
|
* @param null|ActionScheduler_Action $action The instance of the action. Default to null for backward compatibility.
|
|
|
|
*/
|
|
|
|
public function after_execute( $action_id, $action = null ) {
|
|
|
|
// backward compatibility
|
|
|
|
if ( null === $action ) {
|
|
|
|
$action = $this->store->fetch_action( $action_id );
|
|
|
|
}
|
|
|
|
/* translators: %s refers to the action ID */
|
2019-12-02 21:38:21 +00:00
|
|
|
WP_CLI::log( sprintf( __( 'Completed processing action %s with hook: %s', 'woocommerce' ), $action_id, $action->get_hook() ) );
|
2019-03-28 05:31:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Handle WP CLI message when the action has failed.
|
|
|
|
*
|
|
|
|
* @author Jeremy Pry
|
|
|
|
*
|
|
|
|
* @param int $action_id
|
|
|
|
* @param Exception $exception
|
|
|
|
* @throws \WP_CLI\ExitException With failure message.
|
|
|
|
*/
|
|
|
|
public function action_failed( $action_id, $exception ) {
|
|
|
|
WP_CLI::error(
|
|
|
|
/* translators: %1$s refers to the action ID, %2$s refers to the Exception message */
|
2019-12-02 21:38:21 +00:00
|
|
|
sprintf( __( 'Error processing action %1$s: %2$s', 'woocommerce' ), $action_id, $exception->getMessage() ),
|
2019-03-28 05:31:13 +00:00
|
|
|
false
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Sleep and help avoid hitting memory limit
|
|
|
|
*
|
|
|
|
* @param int $sleep_time Amount of seconds to sleep
|
|
|
|
*/
|
|
|
|
protected function stop_the_insanity( $sleep_time = 0 ) {
|
|
|
|
if ( 0 < $sleep_time ) {
|
2019-12-02 21:38:21 +00:00
|
|
|
/* translators: 1: sleep time 2: time unit */
|
|
|
|
WP_CLI::warning( sprintf( __( 'Stopped the insanity for %$1d %$2s', 'woocommerce' ), $sleep_time, _n( 'second', 'seconds', $sleep_time, 'woocommerce' ) ) );
|
2019-03-28 05:31:13 +00:00
|
|
|
sleep( $sleep_time );
|
|
|
|
}
|
|
|
|
|
2019-12-02 21:38:21 +00:00
|
|
|
WP_CLI::warning( __( 'Attempting to reduce used memory...', 'woocommerce' ) );
|
2019-03-28 05:31:13 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @var $wpdb \wpdb
|
|
|
|
* @var $wp_object_cache \WP_Object_Cache
|
|
|
|
*/
|
|
|
|
global $wpdb, $wp_object_cache;
|
|
|
|
|
|
|
|
$wpdb->queries = array();
|
|
|
|
|
|
|
|
if ( ! is_object( $wp_object_cache ) ) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
$wp_object_cache->group_ops = array();
|
|
|
|
$wp_object_cache->stats = array();
|
|
|
|
$wp_object_cache->memcache_debug = array();
|
|
|
|
$wp_object_cache->cache = array();
|
|
|
|
|
|
|
|
if ( is_callable( array( $wp_object_cache, '__remoteset' ) ) ) {
|
|
|
|
call_user_func( array( $wp_object_cache, '__remoteset' ) ); // important
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Maybe trigger the stop_the_insanity() method to free up memory.
|
|
|
|
*/
|
|
|
|
protected function maybe_stop_the_insanity() {
|
|
|
|
// The value returned by progress_bar->current() might be padded. Remove padding, and convert to int.
|
|
|
|
$current_iteration = intval( trim( $this->progress_bar->current() ) );
|
|
|
|
if ( 0 === $current_iteration % 50 ) {
|
|
|
|
$this->stop_the_insanity();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|