{"id":94,"date":"2020-09-09T13:37:02","date_gmt":"2020-09-09T13:37:02","guid":{"rendered":"https:\/\/docs.wpvip.com\/?post_type=technical-references&#038;p=94"},"modified":"2025-06-26T22:07:43","modified_gmt":"2025-06-26T22:07:43","slug":"cron-control","status":"publish","type":"page","link":"https:\/\/docs.wpvip.com\/wordpress-on-vip\/cron-control\/","title":{"rendered":"WP-Cron"},"content":{"rendered":"\n<p>VIP\u2019s cron infrastructure leverages&nbsp;<a href=\"https:\/\/developer.wordpress.org\/plugins\/cron\/\" target=\"_blank\" rel=\"noreferrer noopener\">WP-Cron<\/a>&nbsp;provided by WordPress Core, and cron jobs are initiated and regulated by&nbsp;<a href=\"https:\/\/github.com\/Automattic\/Cron-Control\" target=\"_blank\" rel=\"noreferrer noopener\">Automattic\u2019s Cron Control plugin<\/a>. VIP&#8217;s Cron Control provides an optimized SQL table for WordPress Cron events. This approach satisfies the highly concurrent querying commonly seen on VIP sites. Each named event in the queue is handled in parallel with other events, allowing for a large event handling capacity. The VIP cron system orchestrates the activity of the event workers in the different containers, to avoid conflicts with two workers processing the same event.<\/p>\n\n\n\n<p>Cron jobs are best suited for:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Any intensive processing task such as syndicating content between sites or ingesting videos from third-party video services.<\/li>\n\n\n\n<li>Tasks that are not required to run in real-time such as publishing a post at a future date.<\/li>\n\n\n\n<li>Any task that might require more than 300 seconds to complete.<\/li>\n<\/ul>\n\n\n\n<div class=\"a8c-docs-note-block general\">\n<p><strong>Note<\/strong><\/p>\n\n\n\n<p>The functionality of WordPress Core\u2019s\u00a0<code>\/wp-cron.php<\/code>\u00a0is disabled for all sites on WordPress VIP.<\/p>\n<\/div>\n\n\n\n<h2 class=\"wp-block-heading\">Limitations<\/h2>\n\n\n\n<p>Running WP-CLI commands (including custom WP-CLI commands) inside a cron action by calling <code><a href=\"https:\/\/make.wordpress.org\/cli\/handbook\/references\/internal-api\/wp-cli-runcommand\/\">WP_CLI::runcommand()<\/a><\/code> will not work. Instead, the logic and functionality of a WP-CLI command should be added into a custom function, and that function can be scheduled as a cron event.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-the-difference-between-vip-cron-and-wp-cron\">The difference between VIP cron and WP-Cron<\/h2>\n\n\n\n<p>The core WP-Cron relies on page requests to check, schedule and execute a single cron job. This is less than ideal in cached environments where page requests might not reach the origin server. If the page request does reach the origin server it might not be at the specified time and more importantly, it will create an additional page load for that request as a potentially resource-intensive cron job executes. Since the core WP-Cron control can only execute one cron event at a time (every 1 minute), long-running jobs will further delay subsequent cron jobs from running at their scheduled times, potentially creating an everlasting backlog of scheduled tasks. In addition, the cron jobs are stored in the <code>alloptions<\/code> which can be problematic if <code>alloptions<\/code> grows to be over 1 MB in size.<\/p>\n\n\n\n<p>The VIP cron system solves the limitations of the core WP-Cron by:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Storing cron jobs in the <code>wp_a8c_cron_control_jobs<\/code> custom table instead of <code>alloptions<\/code>.<\/li>\n\n\n\n<li>Having <a href=\"https:\/\/github.com\/Automattic\/cron-control-runner\">a dedicated VIP cron control runner <\/a>that checks for jobs that are due to be executed at a polling interval of 30 seconds instead of relying on a page request.<\/li>\n<\/ul>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Executing cron jobs in separate dedicated containers to alleviate any additional load to the application.<\/li>\n\n\n\n<li>Providing the ability to run multiple jobs in parallel instead of one at a time with a maximum of 60 an hour.<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-monitoring-cron\">Monitoring cron jobs<\/h2>\n\n\n\n<p>The VIP cron system is monitored using a series of dedicated authenticated REST API endpoints on each VIP environment. Monitoring ensures that event queues remain within acceptable parameters, that the events within the queue are executed in a timely manner, and that execution is proceeding smoothly.<\/p>\n\n\n\n<p>In addition, cron jobs for a site can be monitored:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>In the <a href=\"https:\/\/docs.wpvip.com\/query-monitor\/#cron\">Cron panel of Query Monitor<\/a>. <\/li>\n\n\n\n<li>With the <code><a href=\"https:\/\/developer.wordpress.org\/cli\/commands\/cron\/event\/list\/\">wp cron event list<\/a><\/code> WP-CLI command.<\/li>\n\n\n\n<li>By <a href=\"https:\/\/docs.wpvip.com\/runtime-logs\/\">retrieving Batch Logs for an environment with VIP-CLI<\/a> or <a href=\"https:\/\/docs.wpvip.com\/vip-dashboard\/health-logs\/\">in the Health &#8211; Runtime Logs panel of the VIP Dashboard<\/a>. <\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-interacting-with-cron-via-code\">Interacting with cron via code<\/h2>\n\n\n\n<p>The VIP cron system is built on top of core WP-Cron and uses the same scheduling and unscheduling hooks as the document in the <a href=\"https:\/\/developer.wordpress.org\/plugins\/cron\/scheduling-wp-cron-events\/\">Plugin Handbook<\/a>:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/developer.wordpress.org\/plugins\/cron\/scheduling-wp-cron-events\/#scheduling-the-task\">Scheduling a recurring event<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/developer.wordpress.org\/reference\/functions\/wp_schedule_single_event\/\">Scheduling one-time events<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/developer.wordpress.org\/plugins\/cron\/scheduling-wp-cron-events\/#unscheduling-tasks\">Unscheduling an upcoming task<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/developer.wordpress.org\/reference\/functions\/wp_unschedule_hook\/\">Deleting all events for a hook<\/a><\/li>\n<\/ul>\n\n\n\n<div class=\"a8c-docs-note-block wp-reference\">\n<p><strong>Note<\/strong><\/p>\n\n\n\n<p>Do not schedule recurring events using <code>wp_schedule_single_event<\/code> repeatedly. Use <code>wp_schedule_event<\/code> instead.<\/p>\n<\/div>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-interacting-with-cron-via-wp-cli\">Interacting with Cron via WP-CLI<\/h2>\n\n\n\n<p>Use the <code>wp cron<\/code> <a href=\"https:\/\/developer.wordpress.org\/cli\/commands\/cron\/\">WP-CLI command<\/a> with <a href=\"https:\/\/docs.wpvip.com\/vip-cli\/\">VIP-CLI<\/a> to list, run, schedule, unschedule, and delete cron events.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-concurrency\">Concurrency<\/h2>\n\n\n\n<p>By default, Cron Control will only run one event of a given type (i.e. with the same action) at any one time. This is designed to avoid issues where multiple events running simultaneously write to the same values in the database, particularly in&nbsp;<code>alloptions<\/code>, causing issues related to data loss.<\/p>\n\n\n\n<p>There can also be improved efficiency when multiple actions are combined to run as one job rather than run as separate cron events.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"h-increasing-cron-event-concurrency\">Increasing Cron Event Concurrency<\/h3>\n\n\n\n<p>Before increasing concurrency for a Cron event, first assess:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>If a Cron event writes data to <a href=\"https:\/\/docs.wpvip.com\/code-quality\/working-with-wp_options\/#h-autoloading\">an option which is autoloaded<\/a>, it is&nbsp;<strong>not&nbsp;safe<\/strong> for increased concurrency.<\/li>\n\n\n\n<li>If low numbers of Cron events are expected at any one time, i.e. less than 5, then it is not beneficial to increase concurrency.<\/li>\n<\/ul>\n\n\n\n<p>To specify the concurrency level for an event, filter the <code>a8c_cron_control_concurrent_event_whitelist<\/code> hook. Add the event to the array using the action name as the key. Then, specify an integer that represents the number of events of that action that can be run concurrently. <\/p>\n\n\n\n<p>In the code example below, <code>my_async_send_ping<\/code> is the action name and the integer <code>10<\/code> is assigned to the number of possible concurrent events:<\/p>\n\n\n\n<div class=\"wp-block-a8c-docs-syntax-highlighting a8c-docs-syntax\"><pre class=\"line-numbers prism-large\" data-start=\"1\"><code class=\"lang-php\"># Increase Cron Control's concurrency limit for my_async_send_ping action to 10\nadd_filter( 'a8c_cron_control_concurrent_event_whitelist', function( $wl ) {\n    $wl['my_async_send_ping'] = 10;\n    return $wl;\n} );\n<\/code><\/pre><textarea aria-hidden=\"true\" class=\"a8c-docs-syntax__copy-textarea\"># Increase Cron Control's concurrency limit for my_async_send_ping action to 10\nadd_filter( 'a8c_cron_control_concurrent_event_whitelist', function( $wl ) {\n    $wl['my_async_send_ping'] = 10;\n    return $wl;\n} );\n<\/textarea><\/div>\n","protected":false},"excerpt":{"rendered":"<p>VIP\u2019s cron infrastructure leverages&nbsp;WP-Cron&nbsp;provided by WordPress Core, and cron jobs are initiated and regulated by&nbsp;Automattic\u2019s Cron Control plugin. VIP&#8217;s Cron Control provides an optimized SQL table for WordPress Cron events. This approach satisfies the highly concurrent querying commonly seen on VIP sites. Each named event in the queue is handled in parallel with other events, [&hellip;]<\/p>\n","protected":false},"author":20,"featured_media":0,"parent":10228,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"jetpack_post_was_ever_published":false,"footnotes":""},"categories":[50],"tags":[71],"code_tag":[],"environment":[68],"class_list":["post-94","page","type-page","status-publish","hentry","category-wordpress-on-vip","tag-tech-ref"],"parsely":{"version":"1.1.0","canonical_url":"https:\/\/docs.wpvip.com\/wordpress-on-vip\/cron-control\/","smart_links":{"inbound":0,"outbound":0},"traffic_boost_suggestions_count":0,"meta":{"@context":"https:\/\/schema.org","@type":"NewsArticle","headline":"WP-Cron","url":"https:\/\/docs.wpvip.com\/wordpress-on-vip\/cron-control\/","mainEntityOfPage":{"@type":"WebPage","@id":"https:\/\/docs.wpvip.com\/wordpress-on-vip\/cron-control\/"},"thumbnailUrl":"","image":{"@type":"ImageObject","url":""},"articleSection":"WordPress on VIP","author":[{"@type":"Person","name":"WordPress VIP Documentation"}],"creator":["WordPress VIP Documentation"],"publisher":{"@type":"Organization","name":"WordPress VIP Documentation","logo":"https:\/\/docs.wpvip.com\/wp-content\/uploads\/sites\/2\/2023\/07\/cropped-cropped-site-logo.png"},"keywords":["tech-ref"],"dateCreated":"2020-09-09T13:37:02Z","datePublished":"2020-09-09T13:37:02Z","dateModified":"2025-06-26T22:07:43Z"},"rendered":"<script type=\"application\/ld+json\" class=\"wp-parsely-metadata\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@type\":\"NewsArticle\",\"headline\":\"WP-Cron\",\"url\":\"https:\\\/\\\/docs.wpvip.com\\\/wordpress-on-vip\\\/cron-control\\\/\",\"mainEntityOfPage\":{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/docs.wpvip.com\\\/wordpress-on-vip\\\/cron-control\\\/\"},\"thumbnailUrl\":\"\",\"image\":{\"@type\":\"ImageObject\",\"url\":\"\"},\"articleSection\":\"WordPress on VIP\",\"author\":[{\"@type\":\"Person\",\"name\":\"WordPress VIP Documentation\"}],\"creator\":[\"WordPress VIP Documentation\"],\"publisher\":{\"@type\":\"Organization\",\"name\":\"WordPress VIP Documentation\",\"logo\":\"https:\\\/\\\/docs.wpvip.com\\\/wp-content\\\/uploads\\\/sites\\\/2\\\/2023\\\/07\\\/cropped-cropped-site-logo.png\"},\"keywords\":[\"tech-ref\"],\"dateCreated\":\"2020-09-09T13:37:02Z\",\"datePublished\":\"2020-09-09T13:37:02Z\",\"dateModified\":\"2025-06-26T22:07:43Z\"}<\/script>","tracker_url":"https:\/\/cdn.parsely.com\/keys\/docs.wpvip.com\/p.js"},"_links":{"self":[{"href":"https:\/\/docs.wpvip.com\/wp-json\/wp\/v2\/pages\/94","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/docs.wpvip.com\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/docs.wpvip.com\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/docs.wpvip.com\/wp-json\/wp\/v2\/users\/20"}],"replies":[{"embeddable":true,"href":"https:\/\/docs.wpvip.com\/wp-json\/wp\/v2\/comments?post=94"}],"version-history":[{"count":36,"href":"https:\/\/docs.wpvip.com\/wp-json\/wp\/v2\/pages\/94\/revisions"}],"predecessor-version":[{"id":24490,"href":"https:\/\/docs.wpvip.com\/wp-json\/wp\/v2\/pages\/94\/revisions\/24490"}],"up":[{"embeddable":true,"href":"https:\/\/docs.wpvip.com\/wp-json\/wp\/v2\/pages\/10228"}],"wp:attachment":[{"href":"https:\/\/docs.wpvip.com\/wp-json\/wp\/v2\/media?parent=94"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/docs.wpvip.com\/wp-json\/wp\/v2\/categories?post=94"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/docs.wpvip.com\/wp-json\/wp\/v2\/tags?post=94"},{"taxonomy":"code_tag","embeddable":true,"href":"https:\/\/docs.wpvip.com\/wp-json\/wp\/v2\/code_tag?post=94"},{"taxonomy":"environment","embeddable":true,"href":"https:\/\/docs.wpvip.com\/wp-json\/wp\/v2\/environment?post=94"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}