no newsletter · no popup

Blog

Engineering notes, release announcements, and the occasional design rationale.

posts
20
latest
2026-11-05
feed
rss.xml →
All posts
  1. #020 latest

    Scheduling restic or borg backups with alerts when they fail: systemd timer, cron or borgmatic

    Four ways to run restic or borg on a schedule and hear about it when a backup fails or never runs: a systemd timer with OnFailure=, cron with a Healthchecks ping, resticprofile and borgmatic. Tested with restic 0.18 and 0.19, including exit 3, stale locks and catch-up after downtime.

  2. #019

    Django periodic tasks without Celery or Redis: 5 Docker Compose setups

    You need clearsessions every night and a report every 15 minutes, and every tutorial adds Celery, beat and Redis. Five setups without them, each with a Compose file: a management command plus supercronic, APScheduler (and why it runs 3 times under gunicorn), Huey on SQLite, django-q2 on your database, and RunWisp.

  3. #018

    Laravel scheduler in Docker: schedule:run with cron, schedule:work or Supervisor?

    Four ways to run Laravel's scheduler in a container, tested on Laravel 12 and 13: which see your env vars, where the output goes, what docker stop does to a running task, and why schedule:run exits 0 when a task fails.

  4. #017

    Nitro scheduled tasks not running in production (Nuxt): 8 things to check

    Your Nuxt scheduledTasks work in nuxi dev and do nothing in production. The experimental.tasks flag, serverless presets that drop tasks without a warning, hosts that stop the process, NODE_ENV=test, node-cluster running each task once per worker, and how to keep a record of runs.

  5. #016

    Bun.cron logs and Bun.cron not running: where the output goes and 8 things to check

    Bun.cron has two forms that behave differently. The OS-level one writes to your crontab, runs from your home directory without your .env, and its output goes to cron's mail. Where the logs are on Linux and macOS, why a job didn't run, timezones, removal, and Bun.cron vs node-cron.

  6. #015

    node-cron runs multiple times in PM2 cluster mode (and @nestjs/schedule too): 7 fixes

    Under pm2 -i 4, every node-cron or @nestjs/schedule job runs four times. Why, and seven ways to make it run once: the NODE_APP_INSTANCE guard, node-cron's distributed option, a fork-mode scheduler, Redis locks, BullMQ and more.

  7. #014

    Vercel Cron jobs not running on self-hosted Next.js (Docker, Coolify, VPS): 4 fixes

    The crons in vercel.json do nothing outside Vercel, and nothing warns you. Four ways to run them on a self-hosted Next.js app, with the CRON_SECRET header, the instrumentation.ts double-run trap and Docker's HOSTNAME gotcha.

  8. #013

    Ubuntu 26.04 Rust coreutils (uutils) vs GNU: what changes for cron and shell scripts

    Which uutils commands behave differently from GNU coreutils on Ubuntu 26.04 and 26.10, tested on 567 commands: mkdir locks, mv and mtime, timeout, date and DST, df, chown. How to check which you have and how to use GNU instead.

  9. #012

    Debian cron vs cronie vs BusyBox crond: CRON_TZ, /etc/cron.d, env vars and syntax compared

    How cron differs on Ubuntu, Debian, Fedora, RHEL, Arch and Alpine: which crons support CRON_TZ, read /etc/cron.d, pass Docker env vars, handle a bad crontab line, and accept seconds, L, W and #. Tested on six distros.

  10. #011

    When does cron's @reboot run? Not when your container restarts

    @reboot runs the first time cron starts after /run was emptied. On a server that's once per boot. In Docker it's once per container, so a restart, or a host reboot with a restart policy, skips it. We tested six crons.

  11. #010

    How to add a cron job from a script, without crontab -e

    The usual one-liner adds the job twice when it runs twice, and a pipe that fails replaces your whole crontab with nothing. We tested it on four distros, plus the /etc/cron.d mistakes cron skips without telling you.

  12. #009

    Where are cron logs? And why your job's output isn't in them

    Cron logs to the journal, /var/log/syslog, /var/log/cron or /var/log/messages, depending on the distro. We ran the same failing job on six of them. None logged its exit code, and two threw its output away.

  13. #008

    How to put a timeout on a cron job, and what it leaves running

    timeout 20m in front of the command is the standard answer. We timed out the same five jobs with GNU, uutils and busybox timeout, systemd and RunWisp. Six of the seven setups left at least one process running.

  14. #007

    We counted 20,254 cron schedules. 63% start at :00.

    Nearly two in three public cron schedules fire at minute zero, and one in five of those set to an hour ask for midnight UTC. What that costs, why sleep $RANDOM doesn't fix it, and what does.

  15. #006

    Cron job not running? Check these 11 things, in order

    The script works when you run it by hand and does nothing from crontab. A checklist that starts with the one question that halves the search: did cron even try?

  16. #005

    How to stop a cron job from running twice at the same time

    Cron starts the next run whether or not the last one finished. flock fixes that in one word, with three gotchas: the exit code, the lock file location, and child processes that keep the lock.

  17. #004

    How to get alerted when a cron job fails (and when it never runs)

    MAILTO, a curl on failure, a heartbeat service, or a scheduler that alerts on its own. What each one catches, what it misses, and the two-layer setup that covers both.

  18. #003

    Your 02:30 cron job might run twice on October 25

    Or not at all next March. We mapped every clock change in 418 time zones and tested six schedulers: which cron lines break, where, and a 30-second check for your own box.

  19. #002

    Docker Compose cron jobs with a web UI: 4 approaches

    Four ways to schedule jobs in a docker-compose stack, why three of them fail silently, and how to get a dashboard that shows every run's exit code and output.

  20. #001

    Why one binary

    RunWisp embeds SQLite, a web dashboard, and a TUI into a single static Go binary. Here's why, and what it costs.

Get started
GPL 3.0 · no accounts · free to self-host

Start in 30 seconds. Ship on your terms.

A single Go binary. If it doesn't earn the disk space, rm it. No account, no signup, no catch.

Install in 30 seconds
curl -fsSL https://get.runwisp.com | sh