signal-bot/scripts/signal-bot.service
Krzysztof kuhy Rudnicki 72482629d9 fix: a signal-api that is not up yet no longer kills the bot at boot
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-30 15:23:42 +02:00

49 lines
2.0 KiB
Desktop File

# Installed to ~/.config/systemd/user/ by scripts/install_service.sh, which
# substitutes @REPO_ROOT@. Edit this template, never the installed copy.
[Unit]
Description=Signal group bot
Documentation=file://@REPO_ROOT@/README.md
# The bot's only outbound dependency is signal-cli-rest-api in Docker. This
# ordering is worth having and is NOT a fix: dockerd being up says nothing
# about whether the container inside it has finished starting, and signal-cli
# then spends further minutes loading the account. systemd cannot express
# "after that container is ready", so the bot retries the connection itself
# (signal_bot/startup.py) and serves an unhealthy /healthz meanwhile.
After=network-online.target docker.service
Wants=network-online.target
# The start limit now only has to catch answers, not outages. A config error
# -- a missing PHONE_NUMBER, a taken port, a container in the wrong mode --
# exits almost instantly and would otherwise spin forever, so five of those
# stop the unit in `failed`, which shows up in `systemctl --user --failed`.
#
# The arithmetic: 5 starts x RestartSec=30 is 120s, comfortably inside the
# 300s window, so a genuine config error still trips the limit. What used to
# trip it was 5 x 5s = 25s of a container being slow to boot; on 2026-08-30
# that left the group with no bot for eight hours.
StartLimitIntervalSec=300
StartLimitBurst=5
[Service]
Type=exec
WorkingDirectory=@REPO_ROOT@
# run.sh execs the interpreter, so this PID is the bot itself.
ExecStart=@REPO_ROOT@/run.sh
# `always`, not `on-failure`: the bot never exits on its own except when
# startup hits something no retry can fix, and that path asks uvicorn to
# shut down cleanly -- so exit 0 must still count as a restart.
Restart=always
RestartSec=30
# The bot writes only its SQLite tally database, inside the repo.
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ProtectHome=read-only
ReadWritePaths=@REPO_ROOT@
ProtectKernelTunables=true
ProtectControlGroups=true
RestrictSUIDSGID=true
[Install]
WantedBy=default.target