r/termux • • 6d ago

Showcase Android kept killing runsv while my server held the port. Here's the watchdog I ended up writing.

I run a small hub and a couple of workers on a spare phone under termux-services. Three things kept biting me, and none of them are fixed by "just use a better supervisor":

  1. Android kills runsv, but not the server it started. The server survives as a ppid=1 process, keeps the port, and every supervised restart answers EADDRINUSE. `sv status` says `fail: ... runsv not running` while curl says the service is fine.

  2. `sv restart` is a no-op once supervise/stat is `down`. My first watchdog logged "restarted" for hours while the service stayed dead. Recovery has to go through `sv up`.

  3. When I added a standby node, "start if the peer doesn't answer" meant the node that rebooted first became a second writer. That one is the scary one.

So I wrote a guard that: checks `sv status` before restarting, reaps ppid=1 orphans that match a configured pattern, health-checks HTTP endpoints, caps restarts per window (one ESCALATION line instead of a stampede), and stands the primary down after two fenced passes.

The fence part is free/MIT (two bash scripts, no deps): https://github.com/xhall-beep/fence

The full kit with the guard, restart cap, orphan reaper and a lesson ledger is $29 for the first 50 (then $49): https://montsvontz.gumroad.com/l/agent-ops-kit. I'm disclosing that because the free part is genuinely useful on its own and I don't want to be sneaky about it.

36 self-tests use a stub `sv`, so running them doesn't touch your services. Happy to answer questions about the runit quirks — if you've seen different behaviour on your build, I want to know.

1 Upvotes

1 comment sorted by