Scheduling Hugo Posts with AWS CloudWatch

I knew the day would come that I wouldn’t be beside my computer to make a post and manually publish it on my website. Since I’m going on vacation for ten days, I had to find a solution to schedule posts and publish them at specific dates.

I want to keep this website as simple as possible and to have it all serverless. That way I don’t have to worry about security, maintenance, updates and similar. I’ve already written about what AWS services, I’m using, and I’m adding CloudWatch Events (besides Logs) to the tech stack.

Hugo builds a static website, so in order to publish something we need to run hugo command and it will output public directory with our website in it. This post explains the process of building the project using AWS CloudWatch at specific times.

How to Set Up a Cron Job to Build The Project

We’ll reference official AWS documentation for CloudWatch Events with CodeBuild, since it has almost everything we need to set up a cron job. The only problem with documentation (I had), is that I can’t find anywhere CodeBuild Project ARN (Amazon Resource Name), which is step 5 of the documentation. After we find the ARN, you can go back to official documentation and follow along.

How to Find CodeBuild Project ARN

Go to AWS CodeBuild, choose Build History, and choose a build from the project we want. If you don’t have any builds, I recommend you create at least one, since we need it. Click on the one item in “Build run” column (like in the picture below).

You should see the information about the build, the information from there we need is “Build ARN”.

We’ll take the Build ARN and modify it:

arn:aws:codebuild:us-east-1:123456789012:build/my-demo-project:7b7416ae-89b4-46cc-8236-61129df660ad  

We’ll remove the UUID on the end, and rename the “build” part to “project”.

arn:aws:codebuild:us-east-1:123456789012:project/my-demo-project

You can see more info about AWS ARNs here.

Now that you’ve created a CodeBuild ARN, go back to official AWS documentation and finish the setup.

How to Schedule Posts in Hugo

Next step is to set a date at which we want post to be published in Hugo. We just have to add publishDate to front matter.

For example, this post is scheduled for September 1st 2019 at 16:00 GMT, I’ll just add:

publishDate: 2019-09-01T16:00:00+00:00

When we run hugo command, the publishDate variable must be in the past for Hugo to build that post. So if I schedule cron and publishDate at same time, I should get few seconds delay on CodeBuild, which is enough for the publishDate to be in the past and it will be built.

Workflow

If you’ve read my post about hosting serverless hugo on AWS, you’d see that I have a GitHub project that has Git WebHook on it. For those of you who don’t know, Git WebHook (well, WebHooks in general) is a callback that 3rd party systems use to do something with it. My CodeBuild project uses that WebHook and builds the project. Depending on where I commit and push (development or master branch), I get the same WebHook on both CodeBuild project (again, one for development, one for “production”), and see on which branch it was on. In the end, CodeBuild builds the project using hugo --verbose command (--verbose because of CloudWatch Logs) and uploads content of public directory to S3. CloudFront is hooked up to the S3 to deliver the content.

With CloudWatch Event, it just builds the project at specific time. Build is required since Hugo doesn’t build future posts.

Writing Scheduled Posts

If you can’t see your post, since it’s scheduled in the future, Hugo provides you with an option to build those posts:

hugo server -D --buildFuture

The --buildFuture will build posts that are scheduled so you can see them while writing.

Expiry

Besides publishDate front matter, Hugo also has expiryDate:

the datetime at which the content should no longer be published by Hugo; expired content will not be rendered unless the --buildExpired flag is passed to the hugo command.

You can use the same principles for schedule, and for local development. For schedule, you can set up only one specific date on CloudWatch that is the same as expiryDate. When writing, you can use:

hugo server -D --buildFuture --buildExpired