public function run_event($timestamp, $action, $instance, $force = false)
{
// Validate input data
if (empty($timestamp) || empty($action) || empty($instance)) {
return new \WP_Error('missing-data', __('Invalid or incomplete request data.', 'automattic-cron-control'), array('status' => 400));
}
// Ensure we don't run jobs ahead of time
if (!$force && $timestamp > time()) {
return new \WP_Error('premature', sprintf(__('Job with identifier `%1$s` is not scheduled to run yet.', 'automattic-cron-control'), "{$timestamp}-{$action}-{$instance}"), array('status' => 403));
}
// Find the event to retrieve the full arguments
$event = $this->get_event($timestamp, $action, $instance);
// Nothing to do...
if (!is_array($event)) {
return new \WP_Error('no-event', sprintf(__('Job with identifier `%1$s` could not be found.', 'automattic-cron-control'), "{$timestamp}-{$action}-{$instance}"), array('status' => 404));
}
unset($timestamp, $action, $instance);
// Limit how many events are processed concurrently, unless explicitly bypassed
if (!$force) {
// Prepare event-level lock
$this->prime_event_action_lock($event);
if (!$this->can_run_event($event)) {
return new \WP_Error('no-free-threads', sprintf(__('No resources available to run the job with action action `%1$s` and arguments `%2$s`.', 'automattic-cron-control'), $event['action'], maybe_serialize($event['args'])), array('status' => 429));
}
}
// Mark the event completed, and reschedule if desired
// Core does this before running the job, so we respect that
$this->update_event_record($event);
// Run the event
do_action_ref_array($event['action'], $event['args']);
// Free process for the next event, unless it wasn't set to begin with
if (!$force) {
$this->do_lock_cleanup($event);
}
return array('success' => true, 'message' => sprintf(__('Job with action `%1$s` and arguments `%2$s` executed.', 'automattic-cron-control'), $event['action'], maybe_serialize($event['args'])));
}