Scheduled Posts Workaround
One feature I really miss from WordPress is the ability to schedule posts in the future. I used to post to that blog every Wednesday morning, not by actually getting up and writing a post every Wednesday, but by writing posts whenever I felt inspired, and always scheduling them for the soonest Wednesday that didn’t have a post yet. Now that I’m trying to blog again, I’d like to do the same thing.
But scheduling posts on a static site generator has a small problem: The website is static! So there’s no process running to notice that some data that was in the future is now in the past. The static site generator says basically, “Hugo, what should the site look like right now,” and then Hugo writes that state to disk as HTML files and other assets, and those get served to the browser.
But Hugo does have one feature that will help: By default, Hugo posts have a
date
field in their front matter. If that date is in
the future when hugo
is invoked, the post isn’t put in the output directory,
but once the date’s in the past it is. So I have part of a solution right away.
I can just dates that are in the future in the front matter, and that gets me
almost there.
I say “almost” there because Hugo only looks at this date when it’s running, and
it only runs when the site builds, and right now that only happens when I do a
git push
. So we could have the following scenario: I write a cool blog post,
future date it, and push it. Hugo runs, sees that the date is in the future, and
declines to render the post. Then I get busy and don’t blog for a month. Now
hugo hasn’t had a chance to run since the future date passed, so the post
doesn’t get generated until I start blogging again. What I get out of the box
isn’t, “publish this post in the future,” but rather, “publish this post the
next time I run git push
after the 13th of March.”
I’ve built a workaround for this, which I’m not in love with, but does the job. Here’s the workaround:
- Ask Amplify to generate an Incoming Webhook that triggers a build.
- Write a lambda that calls the webhook
- Write a CloudWatch Events / EventBridge cron rule that triggers the lambda.
When you go to create a Lambda in the console, there’s a template called “Make an HTTPS request” that uses Node. That’s probably the ticket. I modified the example code just a little, since I only ever want to call one endpoint, rather than have request details passed in to the event. Here’s the lambda code:
const https = require('https');
/**
* Trigger a build of the blog so scheduled posts get to be created.
*/
exports.handler = (event, context, callback) => {
const options = {
hostname: 'webhooks.amplify.us-east-1.amazonaws.com',
port: 443,
path: process.env.WEBHOOK,
headers: {
'Content-Type': 'application/json'
},
method: 'POST'
}
const req = https.request(options, (res) => {
let body = '';
console.log('Status:', res.statusCode);
console.log('Headers:', JSON.stringify(res.headers));
res.setEncoding('utf8');
res.on('data', (chunk) => body += chunk);
res.on('end', () => {
console.log('Successfully processed HTTPS response');
// If we know it's JSON, parse it
if (res.headers['content-type'] === 'application/json') {
body = JSON.parse(body);
}
callback(null, body);
});
});
req.on('error', callback);
console.log('Sending {} to trigger build');
req.write(JSON.stringify({}));
req.end();
};
And honestly, the most annoying thing to get right was the cron expression,
which looks like this: cron(5 4 * * ? *)
, which I hope means “run at 5 minutes
past 4 AM UTC every day.”
As I’ve said, I’m not in love with this workaround, but it will work, and didn’t take too long to set up. I’ve scheduled the post via this method, so if you’re reading this, I guess it worked.
Till next week, happy learning!
– Will
Love this post? Hate it? Is someone wrong on the internet? Is it me? Please feel free to @me on mastodon
I used to host comments on the blog, but have recently stopped. Previously posted comments will still appear, but for new ones please use the mastodon link above.
Discussion