diff --git a/default/systemd/user/omarchy-update-user-notify.path b/default/systemd/user/omarchy-update-user-notify.path index 2325c828..aaf5233f 100644 --- a/default/systemd/user/omarchy-update-user-notify.path +++ b/default/systemd/user/omarchy-update-user-notify.path @@ -2,7 +2,11 @@ Description=Watch for Omarchy migrations [Path] -PathExistsGlob=/usr/share/omarchy/migrations/*.sh +# Edge-triggered watch only. PathExistsGlob= is level-triggered: it re-fires +# every time the triggered unit deactivates for as long as the glob matches, +# and applied migrations stay on disk forever, so a glob here busy-loops the +# oneshot service. The once-per-login check lives in the service's own +# WantedBy=graphical-session.target instead. PathModified=/usr/share/omarchy/migrations Unit=omarchy-update-user-notify.service diff --git a/default/systemd/user/omarchy-update-user-notify.service b/default/systemd/user/omarchy-update-user-notify.service index 981fbaa7..92f25a65 100644 --- a/default/systemd/user/omarchy-update-user-notify.service +++ b/default/systemd/user/omarchy-update-user-notify.service @@ -1,14 +1,10 @@ [Unit] Description=Notify about pending Omarchy migrations ConditionPathIsDirectory=/usr/share/omarchy/migrations -# A single update can drop several migration files at once, so the .path -# unit re-triggers this oneshot in a burst. Without this, the default -# start-rate limit (5 starts / 10s) trips and the watching .path unit -# itself dies with 'unit-start-limit-hit', silently stopping migration -# notifications for the rest of the session. The notifier is idempotent, -# so disable the start-rate limit. -StartLimitIntervalSec=0 [Service] Type=oneshot ExecStart=/usr/bin/omarchy-migrate-notify + +[Install] +WantedBy=graphical-session.target diff --git a/docs/file-layout.md b/docs/file-layout.md index 08500159..18c4f0f3 100644 --- a/docs/file-layout.md +++ b/docs/file-layout.md @@ -196,9 +196,9 @@ appropriate helper or privilege prompt. Migrations must be idempotent; machine-wide repairs should no-op when another user already applied them. Each graphical user has `omarchy-update-user-notify.path` watching the packaged -migration directory. When that directory changes, or when the path unit is -started on login, `omarchy-update-user-notify.service` runs -`omarchy-migrate-notify` as that user. The notifier checks +migration directory for changes, and `omarchy-update-user-notify.service` is +also started once per login via its own `WantedBy=graphical-session.target`. +Either way the service runs `omarchy-migrate-notify` as that user. The notifier checks `omarchy-migrate --pending`. If this user has missing migration state, it shows a notification that opens a terminal for `omarchy-migrate`. The notifier never runs migrations in the background. @@ -219,7 +219,8 @@ systemd instance: Voxtype post-update hook. - `install/user/first-run/enable-user-units.sh` — `systemctl --user enable` the shipped user units (`bt-agent`, `omarchy-sleep-lock`, - `omarchy-recover-internal-monitor`, `omarchy-update-user-notify.path`). Done here, not at finalize, because + `omarchy-recover-internal-monitor`, `omarchy-update-user-notify.path`, + `omarchy-update-user-notify.service`). Done here, not at finalize, because the user manager isn't reachable from the ISO chroot; `ConditionPath*` in the unit files keeps services inert when they don't apply. - `install/user/first-run/gnome-theme.sh`, diff --git a/install/user/first-run/enable-user-units.sh b/install/user/first-run/enable-user-units.sh index b620df12..efc8123c 100755 --- a/install/user/first-run/enable-user-units.sh +++ b/install/user/first-run/enable-user-units.sh @@ -16,4 +16,5 @@ systemctl --user enable --now \ bt-agent.service \ omarchy-recover-internal-monitor.service \ omarchy-sleep-lock.service \ - omarchy-update-user-notify.path + omarchy-update-user-notify.path \ + omarchy-update-user-notify.service diff --git a/migrations/1784521870.sh b/migrations/1784521870.sh new file mode 100644 index 00000000..55126b60 --- /dev/null +++ b/migrations/1784521870.sh @@ -0,0 +1,10 @@ +echo "Stop the migration notifier from re-triggering itself in a loop" + +# The old omarchy-update-user-notify.path used level-triggered PathExistsGlob, +# which busy-loops the notifier service (or, before r1123, killed the path +# unit with unit-start-limit-hit). Reload the fixed units, revive and restart +# the watcher, and enable the once-per-login notifier. +systemctl --user daemon-reload >/dev/null 2>&1 || true +systemctl --user reset-failed omarchy-update-user-notify.path >/dev/null 2>&1 || true +systemctl --user restart omarchy-update-user-notify.path >/dev/null 2>&1 || true +systemctl --user enable omarchy-update-user-notify.service >/dev/null 2>&1 || true diff --git a/test/shell.d/systemd-test.sh b/test/shell.d/systemd-test.sh index 673ede39..cb9bd169 100755 --- a/test/shell.d/systemd-test.sh +++ b/test/shell.d/systemd-test.sh @@ -27,3 +27,13 @@ grep -F 'ExecStart=%h/.local/share/omarchy/bin/omarchy-system-sleep-monitor' "$u grep -F 'ExecStart=/usr/bin/omarchy-system-sleep-monitor' "$upgrade_to_quattro" >/dev/null grep -F 'reset-failed omarchy-sleep-lock.service' "$upgrade_to_quattro" >/dev/null pass "Omarchy 4 upgrade repairs the legacy sleep lock unit path" + +notify_path="$ROOT/default/systemd/user/omarchy-update-user-notify.path" +! grep -q 'PathExistsGlob' "$notify_path" +grep -Fx 'PathModified=/usr/share/omarchy/migrations' "$notify_path" >/dev/null +pass "migration watcher is edge-triggered so applied migrations on disk cannot re-trigger it" + +notify_service="$ROOT/default/systemd/user/omarchy-update-user-notify.service" +! grep -q 'StartLimit' "$notify_service" +grep -Fx 'WantedBy=graphical-session.target' "$notify_service" >/dev/null +pass "migration notifier keeps its start-rate limit and still runs once per login"