/** * Create a post object for a given event * * Can't call `wp_insert_post()` because `wp_unique_post_slug()` breaks the plugin's expectations * Also doesn't call `wp_insert_post()` because this function is needed before post types and capabilities are ready. */ public function create_or_update_job($timestamp, $action, $args, $update_id = null) { // Limit how many events to insert at once if (!Lock::check_lock(self::LOCK, JOB_CREATION_CONCURRENCY_LIMIT)) { return false; } global $wpdb; // Build minimum information needed to create a post $instance = md5(serialize($args['args'])); $job_post = array('post_title' => $this->event_title($timestamp, $action, $instance), 'post_name' => $this->event_name($timestamp, $action, $instance), 'post_content_filtered' => maybe_serialize(array('action' => $action, 'instance' => $instance, 'args' => $args)), 'post_date' => date('Y-m-d H:i:s', $timestamp), 'post_date_gmt' => date('Y-m-d H:i:s', $timestamp), 'post_modified' => current_time('mysql'), 'post_modified_gmt' => current_time('mysql', true), 'post_type' => self::POST_TYPE, 'post_status' => self::POST_STATUS_PENDING, 'post_author' => 0, 'post_parent' => 0, 'comment_status' => 'closed', 'ping_status' => 'closed'); // Some sanitization in place of `sanitize_post()`, which we can't use this early foreach (array('post_title', 'post_name', 'post_content_filtered') as $field) { $job_post[$field] = sanitize_text_field($job_post[$field]); } // Duplicate some processing performed in `wp_insert_post()` $charset = $wpdb->get_col_charset($wpdb->posts, 'post_title'); if ('utf8' === $charset) { $job_post['post_title'] = wp_encode_emoji($job_post['post_title']); } $job_post = wp_unslash($job_post); // Set this so it isn't empty, even though it serves us no purpose $job_post['guid'] = esc_url(add_query_arg(self::POST_TYPE, $job_post['post_name'], home_url('/'))); // Create the post, or update an existing entry to run again in the future if (is_int($update_id) && $update_id > 0) { $inserted = $wpdb->update($wpdb->posts, $job_post, array('ID' => $update_id)); $this->posts_to_clean[] = $update_id; } else { $inserted = $wpdb->insert($wpdb->posts, $job_post); } // Clear caches for new posts once the post type is registered if ($inserted) { $this->posts_to_clean[] = $wpdb->insert_id; } // Delete internal cache wp_cache_delete(self::CACHE_KEY); // Allow more events to be created Lock::free_lock(self::LOCK); }
/** * Are resources available to run this event? * * @param $event array Event data * * @return bool */ private function can_run_event($event) { // Limit to one concurrent execution of a specific action if (!Lock::check_lock($this->get_lock_key_for_event_action($event), 1, JOB_LOCK_EXPIRY_IN_MINUTES * \MINUTE_IN_SECONDS)) { return false; } // Internal Events aren't subject to the global lock if (is_internal_event($event['action'])) { return true; } // Check if any resources are available to execute this job // If not, the indivdual-event lock must be freed, otherwise it's deadlocked until it times out if (!Lock::check_lock(self::LOCK, JOB_CONCURRENCY_LIMIT)) { $this->reset_event_lock($event); return false; } // Let's go! return true; }