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

a small daemon, in go, actually shipped

A tiny Go daemon that watches a directory and posts to a webhook, and why the boring parts (signals, systemd) took the most thought.

A terminal showing Go source code

I wrote a daemon at the weekend and, against the run of play, finished it. It watches a directory with fsnotify, debounces the events for a second so a burst of writes becomes one, and posts a small JSON payload to a webhook. About 120 lines. The point wasn't the feature, it was getting the dull bits right.

The dull bits are signals and lifecycle. A daemon that doesn't handle SIGTERM cleanly is a daemon that loses work when systemd restarts it. So a context, a signal.NotifyContext, and every goroutine selecting on ctx.Done():

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

Then a systemd unit with Type=simple, Restart=on-failure, and a RestartSec so a crash loop doesn't hammer the box. No PID files, no double-forking, none of the old daemonising rituals. systemd holds the process, journald holds the logs, and I get to write plain code that logs to stdout.

That's the bit I keep relearning. The Go is trivial. The thing that makes it a daemon rather than a script is behaving well when something tells it to stop.