Scheduling cache warming with cron

Pre-hit expensive or cold paths on a schedule so real users never pay the first-request cost.

The problem

Cache warming exists because the first request after a cache expiry or deploy is slow — a cold homepage query, an unbuilt CDN edge object, an empty in-memory LRU after a restart. Left alone, that cost lands on whichever real user happens to hit the endpoint first (or, at deploy time, every user for a few minutes).

The naive version is a curl loop with no timeout: if the endpoint is slow specifically because the cache is cold, the warming request can hang for the request's full timeout, and a second scheduled warm-up starts stacking behind it, quietly generating a load spike disguised as a cache-warming job.

Recommended schedule

*/10 * * * *

Every 10 minutes keeps hot paths from ever fully expiring on a typical 15-minute TTL. Match the interval to your actual cache TTL — warming more often than the TTL is wasted load, less often defeats the point. See /cron for other interval expressions.

Example crontab entry

# norc: cache-warm Pre-warm top listing pages
*/10 * * * * /usr/bin/flock -n /tmp/cache-warm.lock /opt/scripts/warm.sh >> /var/log/cache-warm.log 2>&1
#!/usr/bin/env bash
set -euo pipefail
urls=(https://example.com/ https://example.com/pricing https://example.com/docs)
for u in "${urls[@]}"; do
  curl -s -o /dev/null -w "%{http_code} %{time_total}s $u\n" --max-time 10 "$u"
done

Failure modes to watch for

  • No request timeout: a genuinely cold, slow endpoint makes the warming curl hang, and unlocked overlapping runs pile on more concurrent hits.
  • Warming a deploy-triggered cache with a time-based schedule instead of an event hook — cron fires on a clock, but the cache actually goes cold on every deploy, so the schedule and the real trigger drift apart.
  • Warming requests inflate analytics or rate-limit counters because they hit the same endpoint real users do without a distinguishing header.
  • Warming an authenticated or personalized path with a shared/test account, silently caching one user's data for everyone.

How norc helps

norc's run history shows how long each warm-up took and whether it's creeping toward the timeout — useful for catching a cache that's drifting from "warm" to "always cold" before users notice.