swarm-controller: separate the two paths that re-register a webhook
`ensure_hook` reaches its create call from two different places — the list step failed, or it succeeded and matched nothing — and both were logged at `debug!`. At the level the journal keeps, that made a repeated registration indistinguishable from a first, correct one, and it is a repeated registration that is being observed: the instance-scoped hook logs the create arm on every process start while the repo-scoped one correctly goes quiet. The fold that keeps this harmless (`is_already_exists` swallowing a duplicate create) is an assumption about the forge rather than a guarantee, so the failed-list arm becomes a `warn!`, and the matched-nothing arm logs the number of hooks it did see: `listed=0` is a permission or scope problem, a non-zero count with no match means the recorded url is not the one being compared. No behaviour change — this makes the existing behaviour legible.
This commit is contained in:
parent
5930efc29b
commit
b9d315dcd9
1 changed files with 20 additions and 2 deletions
|
|
@ -610,18 +610,36 @@ impl Client {
|
|||
event: &str,
|
||||
secret: &str,
|
||||
) -> Result<()> {
|
||||
// ⚠️ Both non-matching arms log at a level the journal keeps, because
|
||||
// this idempotency check fails *silently*: when the list step does
|
||||
// not recognise a hook that is already there, the create below runs
|
||||
// again, and that stays harmless only while the forge rejects the
|
||||
// duplicate. A forge that accepts it leaves one extra hook per
|
||||
// process start, each delivering on every event — and the create
|
||||
// arm's line reads exactly like a first, correct registration.
|
||||
//
|
||||
// The two ways to reach a create have different causes, so they are
|
||||
// separated: `listed=0` is a permission or scope problem, a non-zero
|
||||
// count with no match means the recorded url is not the one compared.
|
||||
match scope.list_hook_urls(&self.api).await {
|
||||
Ok(urls) => {
|
||||
if urls.iter().any(|u| u == target_url) {
|
||||
tracing::debug!(%target_url, "swarm forge: webhook already registered");
|
||||
return Ok(());
|
||||
}
|
||||
tracing::info!(
|
||||
%target_url,
|
||||
listed = urls.len(),
|
||||
"swarm forge: no listed hook matches; registering"
|
||||
);
|
||||
}
|
||||
Err(e) => {
|
||||
// Best-effort, same as the per-hive registrars: a forge that
|
||||
// cannot be listed may still accept a create, and a
|
||||
// duplicate create is folded into success below.
|
||||
tracing::debug!(error = %e, %target_url, "swarm forge: listing hooks failed; attempting create");
|
||||
// duplicate create is folded into success below. `warn!`
|
||||
// because that fold is an assumption about the forge, not a
|
||||
// guarantee — see the note above.
|
||||
tracing::warn!(error = %e, %target_url, "swarm forge: listing hooks failed; registering blind");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue