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.
[sourcecode language=”php”]
define(‘DISABLE_WP_CRON’, true);
[/sourcecode]
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.
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)
[sourcecode language=”python”]
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
)
[/sourcecode]
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.
At this point, you have setup the Lambda function and now configured the frequency at which you want it to run.
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