Watch
0
0
Fork
You've already forked hyperhive
0

start the forge and github pollers when their token lands late

Both pollers wait about ten minutes for the agent's token, then exit 0.
Under Restart=on-failure that exit is final, and nothing started them
again, so a token minted or placed after the window left the agent
without notifications until its container restarted.

Add a path unit per poller with PathChanged on the token file(s) the
poller reads, the shape forge-avatar-sync already uses. A path unit
starts its service only when it is not running, so a poller that found
its token is untouched. The github path unit is gated on
github.enable like its service.

Container-side: it ships with the agent's next rebuild, and an agent on
an older rev keeps the old behaviour.

Closes #6179
This commit is contained in:
atlas 2026-11-07 06:25:38 +01:00 • committed by mara
commit fae9398295
4 changed files with 70 additions and 1 deletions

View file

@ -181,6 +181,21 @@ in
};
};
# Starts the poller when a token appears after it gave up waiting for one
# (the poller waits about ten minutes, then exits 0, which `on-failure`
# does not restart). A path unit starts its service only when it is not
# running, so it costs nothing while the poller runs. Both files the poller
# reads are watched. `PathChanged=` for the reason given on
# `forge-avatar-sync` below.
systemd.paths.hive-forge-notify = {
description = "start hive-forge-notify when the forge token appears";
wantedBy = [ "multi-user.target" ];
pathConfig.PathChanged = [
fetchedTokenFile
stateTokenFile
];
};
# Path-trigger sibling: re-fires forge-avatar-sync when the fetched
# forge token (./forge-token.nix) appears or is replaced. On first
# agent deployment the container can boot before the swarm has minted

View file

@ -127,5 +127,18 @@ in
Group = userName;
};
};
# Starts the poller when the token appears after it gave up waiting for one
# (about ten minutes, then exit 0, which `on-failure` does not restart).
# The operator places the PAT through the swarm after the agent runs, so
# that is the usual order. A path unit starts its service only when it is
# not running. `PathChanged=` because the fetch renames the file into place,
# and a `PathExists=` that already holds would re-fire on every re-arm.
# Gated on the service it triggers.
systemd.paths.hive-github-notify = lib.mkIf config.services.hyperhive.agent.github.enable {
description = "start hive-github-notify when the GitHub token appears";
wantedBy = [ "multi-user.target" ];
pathConfig.PathChanged = "/agents/${userName}/state/github-token";
};
};
}

View file

@ -195,6 +195,23 @@ let
agentForgeBao.systemd.paths.forge-avatar-sync.pathConfig.PathChanged == tokenFile agentForgeBao
&& builtins.elem "hive-agent-forge-token.service" agentForgeBao.systemd.services.forge-avatar-sync.after;
}
{
# The poller waits for the token about ten minutes and then exits 0, which
# `on-failure` does not restart; the path unit starts it when either file
# it reads appears. Control: the avatar watcher beside it, in the same set.
name = "a token that lands after the forge poller gave up starts it again";
ok =
let
path = agentForgeBao.systemd.paths.hive-forge-notify;
in
path.pathConfig.PathChanged == [
(tokenFile agentForgeBao)
"/agents/${agentForgeBao.services.hyperhive.agent.user.name}/state/forge-token"
]
&& path.wantedBy == [ "multi-user.target" ]
&& agentForgeBao.systemd.services ? hive-forge-notify
&& agentForgeBao.systemd.paths ? forge-avatar-sync;
}
{
# Both readers take the fetched token first and fall back to the state
# file, which is still the only copy for an agent with no store identity.

View file

@ -102,6 +102,21 @@ let
name = "the fetch runs before the github poller starts";
ok = builtins.elem "hive-github-notify.service" (fetchUnit agentGithubBao).before;
}
{
# The poller waits for the token about ten minutes and then exits 0, which
# `on-failure` does not restart; the path unit starts it when the token lands.
name = "a token that lands after the github poller gave up starts it again";
ok =
let
name = agentGithubBao.services.hyperhive.agent.user.name;
path = agentGithubBao.systemd.paths.hive-github-notify;
in
path.pathConfig.PathChanged == "/agents/${name}/state/github-token"
&& path.wantedBy == [ "multi-user.target" ]
&& agentGithubBao.systemd.services ? hive-github-notify
&& !(agentGithubOff.systemd.paths ? hive-github-notify)
&& !(agentGithubOff.systemd.services ? hive-github-notify);
}
{
name = "the fetch re-runs every two minutes";
ok = agentGithubBao.systemd.timers.hive-agent-github-token.timerConfig.OnUnitInactiveSec == "2min";