How I Setup a WordPress Cron Job Using AWS Lambda

A little background on WordPress cron jobs and why they’re important. WordPress cron jobs is the tool that WordPress core uses to regularly run specific functions. For example, a widely used caching plugin, W3 Total Cache (which I use on many of my sites) can preload caches at regular intervals, to ensure that a page is always cached.

WordPress by default though, triggers this when someone visits your site. This can cause a delay in loading the page though, if it takes a while for a job or jobs, to run. (more info: developer.wordpress.org)

Personally, I disable the built-in WordPress cron and I use a server to run it.

You can disable it by adding this constant to your wp-config.php file.

define('DISABLE_WP_CRON', true);

WordPress on AWS

I want preface this tutorial that this is tailored to working with WordPress specifically in the AWS ecosystem. For more information on it, head over to my walk-through on Cloudflare, Amazon, and Nginx.

Step 1: Identify your EC2 Instance

Within my setup, I have a load balancer (aws.amazon.com) which sites in front of my EC2 instances. So in my ideal world, I really don’t want the cron URL fetch happening out on the Internet.

My first step is to identify the internal IP address of my EC2 instance. I have a number of EC2 instances in my cluster, but I have a single EC2 instance which I want this running on.

You can find this by going to AWS Console > EC2 > Instances > Instances, and then select your instance. As shown below, you can find your internal IP.

AWS Console: Select an EC2 instance

Step 2: Create the Lambda Function

Next step, head over to AWS Lambda. (Navigation: AWS Console > Lambda)

Click “Create function”

I am using Python to accomplish what I am doing with Lambda. Select “Python 3.x” (3.8 is latest, at the time of writing)

RELATED  Using Cloudflare, an Amazon Load Balancer, with Nginx and Fail2Ban

Lamba Function: Generic Cron Job

import urllib3
import os
import random
import string

def randomString(stringLength=10):
    letters = string.ascii_lowercase
    return ''.join(random.choice(letters) for i in range(stringLength))

def cron_handler(event,context):
    
    url = 'http://your_private_ip_here/wp-cron.php?lambda_doing_cron_' + randomString()
    headers = {'Host': event['hostname']}
    
    http = urllib3.PoolManager()
    r = http.request(
        'GET', 
        url, 
        headers=headers
        )

In my use case, I have multiple domains on a single server, and they are all name-based virtual hosts — which is the most common scenario. So instead of hardcoding a domain, I’m using my private IP address (found in Step 1) and then passing a “Host” header in the request. You will see where to set the Host in Step 3.

You must update the “Handler” to point to your filename and function. In my case, I renamed the file (in the folder on the left of the panel) to be “cron.py” and my handler is defined as “cron_handler” therefor, under the Handler input above the function, I have set “cron.cron_handler” as the value.

Feel free to call the function whatever you like. I called my “CRON_Generic”.

Step 3: Setup CloudWatch

Next step is to configure CloudWatch. (Navigation: AWS Console > CloudWatch)

Click into Rules and click “Create Rule”

Select “Schedule” (which is next to Event Pattern)

You can adjust the cron to run at any frequency you wish. I’m using a “Fixed rate of” 1 minute, so the cron will run every single minute. There is also a “cron expression” if you feel like using that.

Next, click “Add target” on the right-hand side of the panel.

In the “Function” drop-down, select the function you created in Step 2.

The last step is to pass in the hostname you want to be called.

CloudWatch: Create Rule for Cron Job

At this point, you have setup the Lambda function and now configured the frequency at which you want it to run.

RELATED  Liveblog at WordCamp OC: Beyond Whitespace with Michelle Schulp

I decided to tail my log files to ensure that it was correctly, on the correct hostname.

The command I use is tail -f /var/www/example.com/logs/access.log (you should replace that log file path with whatever your environment has configured.)

At this point, you’re done!

You no longer have to worry about multiple cron jobs running at the same time, or a visitor being slowed down due to the cron job running in the background. A really nice bonus too, is that AWS provides up to 1M free calls every month. A single site, running at 1 minute intervals, would consume 43,200 calls per month — no where near resulting in billed usage.

Let me know your thoughts in the comments below!

Leave a Reply