Skip to content

Commit

Permalink
Merge pull request #351 from Prospress/fix/350
Browse files Browse the repository at this point in the history
add bulk cancel by hook/group to table store
  • Loading branch information
thenbrent authored Sep 3, 2019
2 parents 1416a11 + 76e149d commit 42c60a6
Show file tree
Hide file tree
Showing 7 changed files with 282 additions and 6 deletions.
19 changes: 19 additions & 0 deletions classes/abstracts/ActionScheduler_Logger.php
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ public function init() {
add_action( 'action_scheduler_execution_ignored', array( $this, 'log_ignored_action' ), 10, 2 );
add_action( 'action_scheduler_failed_fetch_action', array( $this, 'log_failed_fetch_action' ), 10, 2 );
add_action( 'action_scheduler_failed_to_schedule_next_instance', array( $this, 'log_failed_schedule_next_instance' ), 10, 2 );
add_action( 'action_scheduler_bulk_cancel_actions', array( $this, 'bulk_log_cancel_actions' ), 10, 1 );
}

public function hook_stored_action() {
Expand Down Expand Up @@ -145,4 +146,22 @@ public function log_failed_fetch_action( $action_id, Exception $exception = NULL
public function log_failed_schedule_next_instance( $action_id, Exception $exception ) {
$this->log( $action_id, sprintf( __( 'There was a failure scheduling the next instance of this action: %s', 'action-scheduler' ), $exception->getMessage() ) );
}

/**
* Bulk add cancel action log entries.
*
* Implemented here for backward compatibility. Should be implemented in parent loggers
* for more performant bulk logging.
*
* @param array $action_ids List of action ID.
*/
public function bulk_log_cancel_actions( $action_ids ) {
if ( empty( $action_ids ) ) {
return;
}

foreach ( $action_ids as $action_id ) {
$this->log_canceled_action( $action_id );
}
}
}
76 changes: 71 additions & 5 deletions classes/abstracts/ActionScheduler_Store.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,16 +33,17 @@ abstract public function save_action( ActionScheduler_Action $action, DateTime $
abstract public function fetch_action( $action_id );

/**
* @param string $hook
* @param array $params
* @return string ID of the next action matching the criteria
* @param string $hook Hook name/slug.
* @param array $params Hook arguments.
* @return string ID of the next action matching the criteria.
*/
abstract public function find_action( $hook, $params = array() );

/**
* @param array $query
* @param array $query Query parameters.
* @param string $query_type Whether to select or count the results. Default, select.
* @return array The IDs of actions matching the query
*
* @return array|int The IDs of or count of actions matching the query.
*/
abstract public function query_actions( $query = array(), $query_type = 'select' );

Expand Down Expand Up @@ -209,6 +210,71 @@ protected function validate_schedule( $schedule, $action_id ) {
}
}

/**
* Cancel pending actions by hook.
*
* @since 3.0.0
*
* @param string $hook Hook name.
*
* @return void
*/
public function cancel_actions_by_hook( $hook ) {
$action_ids = true;
while ( ! empty( $action_ids ) ) {
$action_ids = $this->query_actions(
array(
'hook' => $hook,
'status' => self::STATUS_PENDING,
'per_page' => 1000,
)
);

$this->bulk_cancel_actions( $action_ids );
}
}

/**
* Cancel pending actions by group.
*
* @since 3.0.0
*
* @param string $group Group slug.
*
* @return void
*/
public function cancel_actions_by_group( $group ) {
$action_ids = true;
while ( ! empty( $action_ids ) ) {
$action_ids = $this->query_actions(
array(
'group' => $group,
'status' => self::STATUS_PENDING,
'per_page' => 1000,
)
);

$this->bulk_cancel_actions( $action_ids );
}
}

/**
* Cancel a set of action IDs.
*
* @since 3.0.0
*
* @param array $action_ids List of action IDs.
*
* @return void
*/
private function bulk_cancel_actions( $action_ids ) {
foreach ( $action_ids as $action_id ) {
$this->cancel_action( $action_id );
}

do_action( 'action_scheduler_bulk_cancel_actions', $action_ids );
}

/**
* @return array
*/
Expand Down
29 changes: 29 additions & 0 deletions classes/data-stores/ActionScheduler_DBLogger.php
Original file line number Diff line number Diff line change
Expand Up @@ -114,4 +114,33 @@ public function clear_deleted_action_logs( $action_id ) {
global $wpdb;
$wpdb->delete( $wpdb->actionscheduler_logs, [ 'action_id' => $action_id, ], [ '%d' ] );
}

/**
* Bulk add cancel action log entries.
*
* @param array $action_ids List of action ID.
*/
public function bulk_log_cancel_actions( $action_ids ) {
if ( empty( $action_ids ) ) {
return;
}

/** @var \wpdb $wpdb */
global $wpdb;
$date = as_get_datetime_object();
$date_gmt = $date->format( 'Y-m-d H:i:s' );
ActionScheduler_TimezoneHelper::set_local_timezone( $date );
$date_local = $date->format( 'Y-m-d H:i:s' );
$message = __( 'action canceled', 'action-scheduler' );
$format = '(%d, ' . $wpdb->prepare( '%s, %s, %s', $message, $date_gmt, $date_local ) . ')';
$sql_query = "INSERT {$wpdb->actionscheduler_logs} (action_id, message, log_date_gmt, log_date_local) VALUES ";
$value_rows = [];

foreach ( $action_ids as $action_id ) {
$value_rows[] = $wpdb->prepare( $format, $action_id );
}
$sql_query .= implode( ',', $value_rows );

$wpdb->query( $sql_query );
}
}
77 changes: 76 additions & 1 deletion classes/data-stores/ActionScheduler_DBStore.php
Original file line number Diff line number Diff line change
Expand Up @@ -394,12 +394,12 @@ public function action_counts() {
*
* @param int $action_id Action ID.
*
* @throws \InvalidArgumentException
* @return void
*/
public function cancel_action( $action_id ) {
/** @var \wpdb $wpdb */
global $wpdb;

$updated = $wpdb->update(
$wpdb->actionscheduler_actions,
[ 'status' => self::STATUS_CANCELED ],
Expand All @@ -413,6 +413,81 @@ public function cancel_action( $action_id ) {
do_action( 'action_scheduler_canceled_action', $action_id );
}

/**
* Cancel pending actions by hook.
*
* @since 3.0.0
*
* @param string $hook Hook name.
*
* @return void
*/
public function cancel_actions_by_hook( $hook ) {
$this->bulk_cancel_actions( [ 'hook' => $hook ] );
}

/**
* Cancel pending actions by group.
*
* @param string $group Group slug.
*
* @return void
*/
public function cancel_actions_by_group( $group ) {
$this->bulk_cancel_actions( [ 'group' => $group ] );
}

/**
* Bulk cancel actions.
*
* @since 3.0.0
*
* @param array $query_args Query parameters.
*/
protected function bulk_cancel_actions( $query_args ) {
/** @var \wpdb $wpdb */
global $wpdb;

if ( ! is_array( $query_args ) ) {
return;
}

// Don't cancel actions that are already canceled.
if ( isset( $query_args['status'] ) && $query_args['status'] == self::STATUS_CANCELED ) {
return;
}

$action_ids = true;
$query_args = wp_parse_args(
$query_args,
[
'per_page' => 1000,
'status' => self::STATUS_PENDING,
]
);

while ( $action_ids ) {
$action_ids = $this->query_actions( $query_args );
if ( empty( $action_ids ) ) {
break;
}

$format = array_fill( 0, count( $action_ids ), '%d' );
$query_in = '(' . implode( ',', $format ) . ')';
$parameters = $action_ids;
array_unshift( $parameters, self::STATUS_CANCELED );

$wpdb->query(
$wpdb->prepare( // wpcs: PreparedSQLPlaceholders replacement count ok.
"UPDATE {$wpdb->actionscheduler_actions} SET status = %s WHERE action_id IN {$query_in}",
$parameters
)
);

do_action( 'action_scheduler_bulk_cancel_actions', $action_ids );
}
}

/**
* Delete an action.
*
Expand Down
10 changes: 10 additions & 0 deletions functions.php
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,16 @@ function as_unschedule_action( $hook, $args = array(), $group = '' ) {
* @param string $group
*/
function as_unschedule_all_actions( $hook, $args = array(), $group = '' ) {
if ( empty( $args ) ) {
if ( ! empty( $hook ) && empty( $group ) ) {
ActionScheduler_Store::instance()->cancel_actions_by_hook( $hook );
return;
}
if ( ! empty( $group ) && empty( $hook ) ) {
ActionScheduler_Store::instance()->cancel_actions_by_group( $group );
return;
}
}
do {
$unscheduled_action = as_unschedule_action( $hook, $args, $group );
} while ( ! empty( $unscheduled_action ) );
Expand Down
38 changes: 38 additions & 0 deletions tests/phpunit/jobstore/ActionScheduler_DBStore_Test.php
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,44 @@ public function test_cancel_action() {
$this->assertInstanceOf( 'ActionScheduler_CanceledAction', $fetched );
}

public function test_cancel_actions_by_hook() {
$store = new ActionScheduler_DBStore();
$actions = [];
$hook = 'by_hook_test';
for ( $day = 1; $day <= 3; $day++ ) {
$delta = sprintf( '+%d day', $day );
$time = as_get_datetime_object( $delta );
$schedule = new ActionScheduler_SimpleSchedule( $time );
$action = new ActionScheduler_Action( $hook, [], $schedule, 'my_group' );
$actions[] = $store->save_action( $action );
}
$store->cancel_actions_by_hook( $hook );

foreach ( $actions as $action_id ) {
$fetched = $store->fetch_action( $action_id );
$this->assertInstanceOf( 'ActionScheduler_CanceledAction', $fetched );
}
}

public function test_cancel_actions_by_group() {
$store = new ActionScheduler_DBStore();
$actions = [];
$group = 'by_group_test';
for ( $day = 1; $day <= 3; $day++ ) {
$delta = sprintf( '+%d day', $day );
$time = as_get_datetime_object( $delta );
$schedule = new ActionScheduler_SimpleSchedule( $time );
$action = new ActionScheduler_Action( 'my_hook', [], $schedule, $group );
$actions[] = $store->save_action( $action );
}
$store->cancel_actions_by_group( $group );

foreach ( $actions as $action_id ) {
$fetched = $store->fetch_action( $action_id );
$this->assertInstanceOf( 'ActionScheduler_CanceledAction', $fetched );
}
}

public function test_claim_actions() {
$created_actions = [];
$store = new ActionScheduler_DBStore();
Expand Down
39 changes: 39 additions & 0 deletions tests/phpunit/jobstore/ActionScheduler_wpPostStore_Test.php
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,45 @@ public function test_cancel_action() {
$this->assertInstanceOf( 'ActionScheduler_CanceledAction', $fetched );
}

public function test_cancel_actions_by_hook() {
$store = new ActionScheduler_wpPostStore();
$actions = array();
$hook = 'by_hook_test';
for ( $day = 1; $day <= 3; $day++ ) {
$delta = sprintf( '+%d day', $day );
$time = as_get_datetime_object( $delta );
$schedule = new ActionScheduler_SimpleSchedule( $time );
$action = new ActionScheduler_Action( $hook, array(), $schedule, 'my_group' );
$actions[] = $store->save_action( $action );
}
$store->cancel_actions_by_hook( $hook );

foreach ( $actions as $action_id ) {
$fetched = $store->fetch_action( $action_id );
$this->assertInstanceOf( 'ActionScheduler_CanceledAction', $fetched );
}
}

public function test_cancel_actions_by_group() {
$store = new ActionScheduler_wpPostStore();
$actions = array();
$group = 'by_group_test';

for ( $day = 1; $day <= 3; $day++ ) {
$delta = sprintf( '+%d day', $day );
$time = as_get_datetime_object( $delta );
$schedule = new ActionScheduler_SimpleSchedule( $time );
$action = new ActionScheduler_Action( 'my_hook', array(), $schedule, $group );
$actions[] = $store->save_action( $action );
}
$store->cancel_actions_by_group( $group );

foreach ( $actions as $action_id ) {
$fetched = $store->fetch_action( $action_id );
$this->assertInstanceOf( 'ActionScheduler_CanceledAction', $fetched );
}
}

public function test_claim_actions() {
$created_actions = array();
$store = new ActionScheduler_wpPostStore();
Expand Down

0 comments on commit 42c60a6

Please sign in to comment.