plugin updates

This commit is contained in:
Tony Volpe
2024-03-01 15:36:30 +00:00
parent ac0ffd7543
commit ed1533dc69
223 changed files with 7575 additions and 2953 deletions

View File

@@ -13,6 +13,7 @@ class ActionScheduler_ActionFactory {
* @param array $args Args to pass to callbacks when the hook is triggered.
* @param ActionScheduler_Schedule $schedule The action's schedule.
* @param string $group A group to put the action in.
* phpcs:ignore Squiz.Commenting.FunctionComment.ExtraParamComment
* @param int $priority The action priority.
*
* @return ActionScheduler_Action An instance of the stored action.
@@ -246,7 +247,6 @@ class ActionScheduler_ActionFactory {
* async_unique(), single() or single_unique(), etc.
*
* @internal Not intended for public use, should not be overriden by subclasses.
* @throws Exception May be thrown if invalid options are passed.
*
* @param array $options {
* Describes the action we wish to schedule.
@@ -263,7 +263,7 @@ class ActionScheduler_ActionFactory {
* @type int $priority Lower values means higher priority. Should be in the range 0-255.
* }
*
* @return int
* @return int The action ID. Zero if there was an error scheduling the action.
*/
public function create( array $options = array() ) {
$defaults = array(
@@ -307,12 +307,27 @@ class ActionScheduler_ActionFactory {
break;
default:
throw new Exception( "Unknown action type '{$options['type']}' specified when trying to create an action for '{$options['hook']}'." );
error_log( "Unknown action type '{$options['type']}' specified when trying to create an action for '{$options['hook']}'." );
return 0;
}
$action = new ActionScheduler_Action( $options['hook'], $options['arguments'], $schedule, $options['group'] );
$action->set_priority( $options['priority'] );
return $options['unique'] ? $this->store_unique_action( $action ) : $this->store( $action );
$action_id = 0;
try {
$action_id = $options['unique'] ? $this->store_unique_action( $action ) : $this->store( $action );
} catch ( Exception $e ) {
error_log(
sprintf(
/* translators: %1$s is the name of the hook to be enqueued, %2$s is the exception message. */
__( 'Caught exception while enqueuing action "%1$s": %2$s', 'action-scheduler' ),
$options['hook'],
$e->getMessage()
)
);
}
return $action_id;
}
/**

View File

@@ -502,7 +502,20 @@ class ActionScheduler_ListTable extends ActionScheduler_Abstract_ListTable {
*/
protected function bulk_delete( array $ids, $ids_sql ) {
foreach ( $ids as $id ) {
$this->store->delete_action( $id );
try {
$this->store->delete_action( $id );
} catch ( Exception $e ) {
// A possible reason for an exception would include a scenario where the same action is deleted by a
// concurrent request.
error_log(
sprintf(
/* translators: 1: action ID 2: exception message. */
__( 'Action Scheduler was unable to delete action %1$d. Reason: %2$s', 'action-scheduler' ),
$id,
$e->getMessage()
)
);
}
}
}

View File

@@ -24,7 +24,37 @@ class ActionScheduler_OptionLock extends ActionScheduler_Lock {
* @bool True if lock value has changed, false if not or if set failed.
*/
public function set( $lock_type ) {
return update_option( $this->get_key( $lock_type ), time() + $this->get_duration( $lock_type ) );
global $wpdb;
$lock_key = $this->get_key( $lock_type );
$existing_lock_value = $this->get_existing_lock( $lock_type );
$new_lock_value = $this->new_lock_value( $lock_type );
// The lock may not exist yet, or may have been deleted.
if ( empty( $existing_lock_value ) ) {
return (bool) $wpdb->insert(
$wpdb->options,
array(
'option_name' => $lock_key,
'option_value' => $new_lock_value,
'autoload' => 'no',
)
);
}
if ( $this->get_expiration_from( $existing_lock_value ) >= time() ) {
return false;
}
// Otherwise, try to obtain the lock.
return (bool) $wpdb->update(
$wpdb->options,
array( 'option_value' => $new_lock_value ),
array(
'option_name' => $lock_key,
'option_value' => $existing_lock_value,
)
);
}
/**
@@ -34,7 +64,30 @@ class ActionScheduler_OptionLock extends ActionScheduler_Lock {
* @return bool|int False if no lock is set, otherwise the timestamp for when the lock is set to expire.
*/
public function get_expiration( $lock_type ) {
return get_option( $this->get_key( $lock_type ) );
return $this->get_expiration_from( $this->get_existing_lock( $lock_type ) );
}
/**
* Given the lock string, derives the lock expiration timestamp (or false if it cannot be determined).
*
* @param string $lock_value String containing a timestamp, or pipe-separated combination of unique value and timestamp.
*
* @return false|int
*/
private function get_expiration_from( $lock_value ) {
$lock_string = explode( '|', $lock_value );
// Old style lock?
if ( count( $lock_string ) === 1 && is_numeric( $lock_string[0] ) ) {
return (int) $lock_string[0];
}
// New style lock?
if ( count( $lock_string ) === 2 && is_numeric( $lock_string[1] ) ) {
return (int) $lock_string[1];
}
return false;
}
/**
@@ -46,4 +99,37 @@ class ActionScheduler_OptionLock extends ActionScheduler_Lock {
protected function get_key( $lock_type ) {
return sprintf( 'action_scheduler_lock_%s', $lock_type );
}
/**
* Supplies the existing lock value, or an empty string if not set.
*
* @param string $lock_type A string to identify different lock types.
*
* @return string
*/
private function get_existing_lock( $lock_type ) {
global $wpdb;
// Now grab the existing lock value, if there is one.
return (string) $wpdb->get_var(
$wpdb->prepare(
"SELECT option_value FROM $wpdb->options WHERE option_name = %s",
$this->get_key( $lock_type )
)
);
}
/**
* Supplies a lock value consisting of a unique value and the current timestamp, which are separated by a pipe
* character.
*
* Example: (string) "649de012e6b262.09774912|1688068114"
*
* @param string $lock_type A string to identify different lock types.
*
* @return string
*/
private function new_lock_value( $lock_type ) {
return uniqid( '', true ) . '|' . ( time() + $this->get_duration( $lock_type ) );
}
}

View File

@@ -103,9 +103,12 @@ class ActionScheduler_QueueRunner extends ActionScheduler_Abstract_QueueRunner {
* should dispatch a request to process pending actions.
*/
public function maybe_dispatch_async_request() {
if ( is_admin() && ! ActionScheduler::lock()->is_locked( 'async-request-runner' ) ) {
// Only start an async queue at most once every 60 seconds
ActionScheduler::lock()->set( 'async-request-runner' );
// Only start an async queue at most once every 60 seconds.
if (
is_admin()
&& ! ActionScheduler::lock()->is_locked( 'async-request-runner' )
&& ActionScheduler::lock()->set( 'async-request-runner' )
) {
$this->async_request->maybe_dispatch();
}
}

View File

@@ -226,7 +226,7 @@ abstract class ActionScheduler {
__( '%s() was called before the Action Scheduler data store was initialized', 'action-scheduler' ),
esc_attr( $function_name )
);
error_log( $message );
_doing_it_wrong( $function_name, $message, '3.1.6' );
}
return self::$data_store_initialized;

View File

@@ -91,7 +91,7 @@ abstract class ActionScheduler_Abstract_QueueRunner extends ActionScheduler_Abst
} catch ( Throwable $e ) {
// Throwable is defined when executing under PHP 7.0 and up. We convert it to an exception, for
// compatibility with ActionScheduler_Logger.
throw new Exception( $e->getMessage(), $e->getCode(), $e->getPrevious() );
throw new Exception( $e->getMessage(), $e->getCode(), $e );
}
} catch ( Exception $e ) {
// This catch block exists for compatibility with PHP 5.6.

View File

@@ -26,6 +26,8 @@ abstract class ActionScheduler_Lock {
/**
* Set a lock.
*
* To prevent race conditions, implementations should avoid setting the lock if the lock is already held.
*
* @param string $lock_type A string to identify different lock types.
* @return bool
*/

View File

@@ -347,7 +347,7 @@ abstract class ActionScheduler_Store extends ActionScheduler_Store_Deprecated {
'hook' => $hook,
'status' => self::STATUS_PENDING,
'per_page' => 1000,
'orderby' => 'action_id',
'orderby' => 'none',
)
);
@@ -372,7 +372,7 @@ abstract class ActionScheduler_Store extends ActionScheduler_Store_Deprecated {
'group' => $group,
'status' => self::STATUS_PENDING,
'per_page' => 1000,
'orderby' => 'action_id',
'orderby' => 'none',
)
);

View File

@@ -82,7 +82,7 @@ class ActionScheduler_DBLogger extends ActionScheduler_Logger {
}
/**
* Retrieve the an action's log entries from the database.
* Retrieve an action's log entries from the database.
*
* @param int $action_id Action ID.
*

View File

@@ -705,7 +705,7 @@ AND `group_id` = %d
array(
'per_page' => 1000,
'status' => self::STATUS_PENDING,
'orderby' => 'action_id',
'orderby' => 'none',
)
);
@@ -935,7 +935,17 @@ AND `group_id` = %d
$sql = $wpdb->prepare( "{$update} {$where} {$order} LIMIT %d", $params ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQLPlaceholders
$rows_affected = $wpdb->query( $sql ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
if ( false === $rows_affected ) {
throw new \RuntimeException( __( 'Unable to claim actions. Database error.', 'action-scheduler' ) );
$error = empty( $wpdb->last_error )
? _x( 'unknown', 'database error', 'action-scheduler' )
: $wpdb->last_error;
throw new \RuntimeException(
sprintf(
/* translators: %s database error. */
__( 'Unable to claim actions. Database error: %s.', 'action-scheduler' ),
$error
)
);
}
return (int) $rows_affected;

View File

@@ -38,6 +38,7 @@ class ActionScheduler_StoreSchema extends ActionScheduler_Abstract_Schema {
$table_name = $wpdb->$table;
$charset_collate = $wpdb->get_charset_collate();
$max_index_length = 191; // @see wp_get_db_schema()
$hook_status_scheduled_date_gmt_max_index_length = $max_index_length - 20 - 8; // - status, - scheduled_date_gmt
$default_date = self::DEFAULT_DATE;
switch ( $table ) {
@@ -59,8 +60,8 @@ class ActionScheduler_StoreSchema extends ActionScheduler_Abstract_Schema {
claim_id bigint(20) unsigned NOT NULL default '0',
extended_args varchar(8000) DEFAULT NULL,
PRIMARY KEY (action_id),
KEY hook (hook($max_index_length)),
KEY status (status),
KEY hook_status_scheduled_date_gmt (hook($hook_status_scheduled_date_gmt_max_index_length), status, scheduled_date_gmt),
KEY status_scheduled_date_gmt (status, scheduled_date_gmt),
KEY scheduled_date_gmt (scheduled_date_gmt),
KEY args (args($max_index_length)),
KEY group_id (group_id),