Ballyhoo, the show out front
A ballyhoo is the free mini show a carnival puts on outside a tent to attract people in off the midway. That's this blog's job too - every experiment I publish gets written up here, so people can find it and I can get feedback.
What it's made of
Some fairly simple Elixir modules. Posts are Markdown, written in a little admin page with a live preview - and the preview isn't a separate renderer trying to approximate the real thing, it's the same function that renders the published page.
The data sits in SQLite, accessed via Ash framework, and every edit keeps a revision - mostly so I don't accidentally nuke a paragraph I actually wanted. Code blocks get syntax highlighting in both light and dark, and mermaid diagrams are rendered client side.
The part I actually wanted to spend some time on
What if a blog post does okay? A link from somewhere busy can dump thousands of readers onto a page within a minute, and they're all landing on one small server I'm paying very little for. I didn't want a surprise traffic spike to take the site down, so a reader visiting a page never causes it to be rendered server-side.
Every public blog page - posts, tag pages, the feed, the sitemap - gets rendered once when a post changes, not on each request. The rendered, gzip-compressed result sits in ETS, keyed by its path. Serving a request is one lookup and handing over bytes that were already sitting there. No filesystem access, no templates re-running, no database hit, nothing clever happening while someone's waiting.
Pages also set no cookies and carry an ETag plus Cache-Control, so browsers and anything in between can just reuse what they already have instead of requesting again.
$ curl -sI -H 'accept-encoding: gzip' https://blog.ubermonkey.net/posts/ballyhoo
...
content-encoding: gzip
etag: "…-gz"
cache-control: public, max-age=60, stale-while-revalidate=600
...
Benchmarking this held up to around 25,000 requests a second off four desktop cores. Past that point, the bottleneck wasn't serving pages at all - it was the cost of setting up new TLS connections. Which is a nice problem to not have yet.