forge: stop the avatar sync retriggering itself into the start limit
`forge-avatar-sync.path` used `PathExists=`. systemd.path(5): a `PathExists=` condition that already holds activates the configured unit immediately whenever the path unit is activated. A `Type=oneshot` unit with `RemainAfterExit=false` deactivates after each run, which re-arms the path, which fires again because the token is still there — an unconditional loop that ends at `StartLimitBurst`. Measured on a container boot carrying the previous fix: five starts and `start-limit-hit` with the glob already removed and exactly one matching file. So the count was never one-per-token; it was the start limit, and scoping the watch (#4025) could not have fixed it. `PathChanged=` does not fire on an already-present path, and hive-priv writes this file in place — `write_state_file_nofollow` opens with `O_TRUNC` and no rename — so close-after-write still triggers it. The token-present-at-boot case stays covered by the service's own `wantedBy = multi-user.target`. Same directive and same reasoning as `swarm-controller.nix`'s queue-credential watcher, which reached it first: "`PathChanged=` requires a write, so it cannot do that and cannot spin." The comment claiming the storm came from many agents' tokens arriving at once is removed with it — that model is what let the defect survive the previous fix. Refs #3984.
This commit is contained in:
parent
529e9416c1
commit
e9faa3896f
1 changed files with 16 additions and 10 deletions
|
|
@ -244,26 +244,32 @@ in
|
|||
'';
|
||||
};
|
||||
|
||||
# Path-trigger sibling: re-fires forge-avatar-sync the moment
|
||||
# `<state>/forge-token` appears. Mirrors the hive-matrix-daemon
|
||||
# token-watcher pattern — on first agent deployment the container
|
||||
# boots before hive-c0re has provisioned the forge-token, so the
|
||||
# service fires too early and exits with "no forge-token found".
|
||||
# Path-trigger sibling: re-fires forge-avatar-sync when
|
||||
# `<state>/forge-token` is written. On first agent deployment the
|
||||
# container boots before hive-c0re has provisioned the forge-token, so
|
||||
# the service fires too early and exits with "no forge-token found".
|
||||
# Without this path unit, RemainAfterExit=true would prevent systemd
|
||||
# from ever re-running the service. See
|
||||
# docs/agent-lifecycle/persistence.md::forge-avatar-sync.
|
||||
#
|
||||
# PathChanged=, not PathExists=: a PathExists= condition that already
|
||||
# holds re-activates the unit immediately every time the path unit
|
||||
# re-arms, and a oneshot re-arms it by deactivating — so it loops until
|
||||
# systemd's start limit stops it. PathChanged= does not fire on an
|
||||
# already-present path, and hive-priv writes this file in place
|
||||
# (write_state_file_nofollow: O_TRUNC, no rename), so close-after-write
|
||||
# still triggers it. Same directive and same reason as
|
||||
# swarm-controller.nix's queue-credential watcher.
|
||||
#
|
||||
# ⚠️ This agent's own token, not a glob over `/agents/*/`. Every agent's
|
||||
# state dir is visible from inside every container, so a wildcard here
|
||||
# watches paths this unit has no business reacting to: each sibling's
|
||||
# token appearing re-fires *this* agent's sync, and enough of them
|
||||
# arriving at once trips systemd's start rate limit — leaving a red
|
||||
# `[FAILED]` on every boot after the upload has already succeeded.
|
||||
# watches paths this unit has no business reacting to.
|
||||
# The service reads `$HYPERHIVE_STATE_DIR/forge-token`; this is the same
|
||||
# file, spelled the way `tea-login` above already spells it.
|
||||
systemd.paths.forge-avatar-sync = lib.mkIf (config.hyperhive.icon != null) {
|
||||
description = "trigger forge-avatar-sync when forge-token appears";
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
pathConfig.PathExists = "/agents/${userName}/state/forge-token";
|
||||
pathConfig.PathChanged = "/agents/${userName}/state/forge-token";
|
||||
};
|
||||
|
||||
# One-shot: hyperhive.icon → Forgejo profile avatar. Shape contract:
|
||||
|
|
|
|||
Loading…
Reference in a new issue