LibrePortal/scripts/crontab/system/crontab_setup_system_info_updater.sh
librelad 0e98988fcb fix(boot): reconcile apps at startup — unless-stopped loses a shutdown race
Prometheus kept being found stopped after boots, always Exited(0),
always alone. The journal settles it: both stops sit seconds before a
host shutdown boundary — container stopped 05:45:22, boot ended
05:45:30; stopped 04:41:59, boot ended 04:42:05. This is a laptop-class
host that gets shut down, and under ROOTLESS docker the containers are
ordinary processes in the user session, torn down by systemd in
parallel with dockerd's own exit.

That parallelism is the race. An app that handles SIGTERM promptly
exits while dockerd is still alive to record "stopped" — and
unless-stopped then means what it says: not restarted at the next
boot. Apps that exit slower, or die only when dockerd does, are
recorded as running and come back. Prometheus loses reliably because it
is the best-behaved process on the box ("See you next time!"), but
which app loses is a scheduling accident — changing Prometheus's
restart policy would treat the sample, not the race.

So an @reboot crontab entry now waits for the rootless daemon (up to
five minutes, then gives up rather than hang) and `compose up -d`s
every installed app via the existing dockerComposeUpAllApps. Idempotent:
running apps see no diff, stopped ones start, ordering is compose's
problem. Registered through crontabRefresh like the other entries, and
installed on this box.

The accepted trade, stated rather than hidden: an app deliberately
stopped before a reboot comes back after it. On a self-hosting box "the
fleet is up after boot" is the promise unless-stopped was already trying
to make; a stop that must survive reboots is what uninstall is for.

Verified by direct execution: daemon answered immediately, all
installed apps reconciled, running containers untouched.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-21 00:49:51 +01:00

32 lines
1.2 KiB
Bash
Executable File

#!/bin/bash
crontabSetupSystemInfoUpdater()
{
local cronEntry="* * * * * libreportal webui generate system >/dev/null 2>&1"
# Check if already in crontab
if runAsManager crontab -l 2>/dev/null | grep -q "libreportal webui generate system"; then
isNotice "System info updater already in crontab"
else
# Add to crontab
(runAsManager crontab -l 2>/dev/null; echo "$cronEntry") | runAsManager crontab -
isSuccessful "System info updater added to crontab (every 1 minute)."
fi
}
# @reboot: bring every installed app back up once the rootless daemon answers.
# Exists because restart:unless-stopped loses a shutdown race under rootless
# docker — see crontab_boot_app_reconcile.sh for the full account.
crontabSetupBootAppReconcile()
{
local cronEntry="@reboot ${install_scripts_dir}crontab/system/crontab_boot_app_reconcile.sh start_script >/dev/null 2>&1"
if runAsManager crontab -l 2>/dev/null | grep -q "crontab_boot_app_reconcile.sh"; then
isNotice "Boot app reconcile already in crontab"
else
(runAsManager crontab -l 2>/dev/null; echo "$cronEntry") | runAsManager crontab -
isSuccessful "Boot app reconcile added to crontab (@reboot)."
fi
}