Use Asynchronous PHP in WordPress to Delay Slow Tasks and Improve Response Speed

PHP runs code synchronously, which means one operation is executed after another in sequence. If we need to perform a large number of operations in a single request or call an external API, the whole request may take quite a long time to finish. That leads to long wait times for users, which is a poor user experience. In this article, we will look at ways to execute long-running work asynchronously in WordPress.

Run asynchronous PHP tasks in WordPress with WP Cron

WordPress gives us the WP Cron system, which can be used to schedule tasks. One easy way to make a task asynchronous is to push it into a one-time scheduled event that runs shortly after the current request, so the user does not have to wait for the result immediately.

A good example is the email notification sent to the administrator when someone submits a comment. By default, that operation is synchronous, so WordPress does not report the comment as submitted until the email has been sent successfully. On some hosts, email delivery is slow, and that makes the user wait.

In reality, the administrator does not need to receive the email instantly. Even if the email arrives immediately, the administrator may not read it right away. So it makes sense to tell the user the comment was submitted successfully first and then send the email a little later via a scheduled task.

The following function implements a simple asynchronous mail sender:

if ( ! defined( 'DOING_CRON' ) || ( defined( 'DOING_CRON' ) && ! DOING_CRON ) ) {
   function async_send_wp_mail() {

      // Get the arguments for wp_mail().
      $args = func_get_args();

      // Add a random value to avoid duplicate sends, see:
      // http://codex.wordpress.org/Function_Reference/wp_schedule_single_event
      $args[] = mt_rand();

      // Send the email 5 minutes later.
      wp_schedule_single_event( time() + 5, 'cron_send_mail', $args );
   }
}

When we actually want to send the email, we can do it asynchronously like this:

add_action( 'cron_send_mail', function () {
   $args = func_get_args();

   // Remove the random value added above.
   array_pop( $args );

   call_user_func_array( 'wp_mail', $args );
}, 10, 10 );

Use the WP Asynchronous Tasks library for asynchronous PHP in WordPress

The WP Cron method above is simple, but it can suffer from efficiency problems. If there are many emails or many delayed tasks, the delay may become too large. TechCrunch’s open-source WP Asynchronous Tasks library addresses that problem by using a token-based task mechanism to confirm whether a task succeeded and then continue with the deferred work.

For example, on a post page we may need to fetch related posts that share categories or tags with the current post. That can be a relatively expensive MySQL query, so in practice we usually cache the result. If the cache exists, we display it immediately. If the cache is missing or expired, we refresh the data and then display it.

On a large site, refreshing the cache before rendering the page can make the visitor wait too long. In that case, we can optimize the workflow with asynchronous processing: display the cached data first, check whether the cache is close to expiring, and if necessary queue an asynchronous task to refresh it in the background. That way, the page always shows cached data, and the expensive refresh happens later.

According to TechCrunch, using WP Asynchronous Tasks in the right situations can improve WordPress page load speed by five to eight times. If your site has this kind of bottleneck, that library is worth considering.

Another similar library is WP Background Processing from the makers of WP Migrate DB Pro. It extends the WP Asynchronous Tasks idea with simple queue support. If you need to process a large number of repeated, time-consuming jobs, what you may really want is a full WordPress job queue backed by the database.

Related Posts

Leave a Reply

Your email address will not be published. Required fields are marked *