How We Solved the Producer-Consumer Problem (For Blog Posts)

You know the producer-consumer problem from computer science, right? One process creates stuff, another process consumes it, and if they're not synchronized, chaos ensues.

Turns out, content creation has the exact same problem.


The Problem: Bursty Writers, Consistent Readers

Here's how blog writing actually works:

Producer (Me):

Monday: Write 4 posts in a caffeine-fueled frenzy
Tuesday-Sunday: *crickets*
Next Monday: Panic, write 3 more posts

Consumer (Readers & SEO):

Expectation: Consistent 3x/week publishing
Reality: 4 posts on Monday, nothing for 2 weeks, then 7 posts on a random Tuesday

Google hates inconsistency. Readers forget you exist. Your newsletter goes from "weekly insights" to "occasional ramblings from someone who may or may not still be alive."

Classic producer-consumer mismatch.


The Traditional Solutions (That Don't Work)

1. "Just Be Consistent"

Ah yes, the "just don't have ADHD" approach. Revolutionary.

The problem isn't motivation—it's that creative energy comes in bursts. Some days you write 3,000 words before breakfast. Other days, you stare at a blank screen and contemplate becoming a goat farmer.

2. Use a CMS with Scheduling

WordPress, Ghost, and others have scheduling. But they require:

  • Manual date picking for each post
  • Remembering what you've already scheduled
  • A calendar that doesn't sync with your actual life
  • Discipline (see point #1)

3. Hire a Content Manager

laughs in solo developer budget


Our Solution: Stock-Based Scheduling

We built a simple system with one core idea: treat blog posts like inventory.

The Stock File

{
  "_articleStockWouldLastUpto": "2026-02-26",
  "getting-started-with-jo4": "2026-01-31",
  "api-first-url-shortener": "2026-02-03",
  "claude-code-hooks": "2026-02-05",
  "elasticache-vs-memorydb": "2026-02-07"
}

Each post gets a publishAfter date in its frontmatter. The stock.json file tracks everything:

  • What's scheduled
  • When each post goes live
  • When you'll run out of content

That last field—_articleStockWouldLastUpto—is the magic. It's your inventory level.

The Workflow

When I write (producer):

  1. Create post with content
  2. Set publishAfter to the next available slot
  3. Update stock.json with the new entry
  4. Update _articleStockWouldLastUpto if this is the latest

When GitHub Actions runs (consumer):

  1. Check which posts have publishAfter <= today
  2. Build and publish those posts
  3. Crosspost to dev.to
  4. Check stock levels

The Low Stock Warning

Here's the clever bit. Every day at 1 AM UTC, our CI pipeline checks:

STOCK_DATE=$(jq -r '._articleStockWouldLastUpto' stock.json)
DAYS_LEFT=$(( (STOCK_EPOCH - TODAY_EPOCH) / 86400 ))

if [ "$DAYS_LEFT" -lt 3 ]; then
  echo "LOW STOCK! Only $DAYS_LEFT days remaining!"
  # Send Slack notification
fi

If I have less than 3 days of content queued up, I get a Slack message:

⚠️ LOW ARTICLE STOCK! Only 2 days of scheduled articles remaining. Time to write more blog posts!

It's like a grocery store inventory system, but for words.


Why This Works

1. Decouples Writing from Publishing

I can write 5 posts on a Sunday afternoon and not worry about when they'll go live. The system handles the "when," I handle the "what."

2. Visualizes the Buffer

Seeing _articleStockWouldLastUpto: "2026-02-26" is motivating. It's concrete. "I have 25 days of content" is way more actionable than "I should probably write more."

3. Prevents Feast-or-Famine

The warning system catches problems before they become crises. No more "oh no, I haven't posted in 3 weeks" panic.

4. Works with Bursts

Write 10 posts in a weekend? Great, you just bought yourself a month. The system doesn't care when you write, just that you eventually do.


The Implementation

Post Frontmatter

---
title: "My Post Title"
description: "SEO-friendly description"
blogPath: my-post-slug
publishAfter: "2026-03-02"
author: Jo4 Team
tags:
  - tag1
  - tag2
  - tag3
  - tag4
---

The publishAfter field is the key. Posts with future dates exist in the repo but aren't built into the public site.

Build Logic

// In 11ty config
eleventyConfig.addCollection("posts", function(collection) {
  const today = new Date().toISOString().split('T')[0];
  return collection
    .getFilteredByGlob("posts/**/index.md")
    .filter(post => post.data.publishAfter <= today)
    .sort((a, b) => b.data.publishAfter.localeCompare(a.data.publishAfter));
});

Future posts are filtered out at build time. Simple.

GitHub Actions Cron

schedule:
  - cron: "0 1 * * *"  # Daily at 1 AM UTC

The pipeline runs daily, checks for newly-eligible posts, builds, deploys, and crossposts.


The Meta Irony

Yes, I'm writing a blog post about automating blog posts.

Yes, this post will be scheduled using the system I'm describing.

Yes, I wrote this during a burst of productivity and it's scheduled 3 weeks out.

The system works.


Lessons Learned

  1. Treat creative work like inventory - Buffers smooth out inconsistency
  2. Automate the boring parts - Date calculation, crossposting, warnings
  3. Make the invisible visible - _articleStockWouldLastUpto turns abstract anxiety into concrete numbers
  4. Design for how you actually work - Bursts are fine if the system handles them

Try It Yourself

The full system is:

  • 11ty for static site generation
  • GitHub Actions for scheduling and deployment
  • A simple JSON file for inventory tracking
  • Slack webhook for low-stock alerts

Total lines of custom code: ~50.

Sometimes the best solutions aren't frameworks or SaaS products. Sometimes it's just a JSON file and a cron job.


How do you handle content scheduling? Built your own system, or using something off-the-shelf?

Building jo4.io - URL shortener with analytics. Yes, we practice what we preach with consistent publishing.