Ramblings of an aging IT geek
← Ramblings of an aging IT geek
golang

a forty-line go daemon that's earned its keep

A tiny single-binary Go daemon that does one boring job, handles signals properly, and has quietly replaced a fragile shell-and-cron arrangement.

A monitor showing Go source code

I shipped a daemon this week. It does almost nothing, which is the highest praise I can give it. It watches a directory, and when a file lands it pokes a downstream service, and that's the whole job. It replaced a fragile arrangement of a shell script, a cron entry, and a lock file that the previous post on this blog could have been written about.

The reason it's in Go and not another shell script is the boring stuff, and the boring stuff is the point. A single static binary I can drop on a box with no runtime to install. A real signal handler, so when systemd sends SIGTERM it finishes the file it's mid-way through and exits cleanly instead of leaving half-processed mess behind:

ctx, stop := signal.NotifyContext(context.Background(),
	syscall.SIGINT, syscall.SIGTERM)
defer stop()

That NotifyContext line is the bit shell never gave me cleanly. The context cancels on a signal, every loop checks ctx.Done(), and shutdown is graceful by construction rather than by a tangle of trap statements I'd get subtly wrong.

It's about forty lines, it logs to stderr where journald can find it, and it's been running since Tuesday without a hiccup. No framework, no dependencies worth mentioning, just the standard library doing exactly what it's good at. Not every problem needs a daemon, and plenty of small jobs really are fine as a cron line. But the moment you find yourself bolting lock files and signal traps onto a shell script to make it behave, that's the script telling you it wants to be a small Go binary instead. This one was, and it's happier for it, and so am I.