fix(#2398): graceful restart as one atomic DAG, not compose-and-await

mara's review on #2436: no submit-await-submit composition, even
server-side. Adds Template::GracefulRestart (Signal -> Drain ->
StopForUpdate -> Reconcile, wanted=Up) mirroring how Restart already
does StopForUpdate -> Reconcile, plus submit::graceful_restart and
templates::graceful_restart. handle_restart_scoped now submits exactly
one DAG per agent up front for both the graceful and non-graceful
case -- no await_dags in the loop anymore.
This commit is contained in:
atlas 2026-07-14 20:21:06 +02:00 committed by mara
commit 901ab6a779
8 changed files with 103 additions and 40 deletions

View file

@ -40,16 +40,21 @@ pub enum HostRequest {
/// container list and restarts each one.
RestartAll,
/// Restart containers hive-wide (`hivectl restart`), scoped like
/// `Stop`/`Start`. Each targeted agent rides exactly one DAG server-side
/// (the `Restart` template, hard stop + reconcile — or, when `graceful`
/// is set, a submitted graceful-stop DAG the server itself waits out
/// before submitting the start DAG) rather than the old client-side
/// stop-then-start composition: a dropped `hivectl` connection mid-way
/// used to leave the agent stopped with no automatic follow-up, since
/// nothing durable remembered "finish the restart" once the CLI process
/// was gone. Infra containers have no lease/DAG and restart
/// synchronously (stop then start), same as before. Scope semantics
/// match `Stop`/`Start` (all-false = everything).
/// `Stop`/`Start`. Each targeted agent rides exactly one DAG
/// server-side — the `Restart` template (mechanical stop + reconcile),
/// or, when `graceful` is set, the `GracefulRestart` template (signal →
/// drain → mechanical stop → reconcile) — rather than the old
/// client-side stop-then-start composition (and, briefly, a server-side
/// "submit stop DAG, await it, submit start DAG" composition): a
/// dropped `hivectl` connection mid-way, or a crash between the two
/// submits, used to leave the agent stopped with no automatic
/// follow-up, since nothing durable remembered "finish the restart"
/// once the calling process/turn was gone. `GracefulRestart` closes
/// that gap the same way `Restart` already does — one DAG, queued up
/// front, that owns the whole sequence. Infra containers have no
/// lease/DAG and restart synchronously (stop then start), same as
/// before. Scope semantics match `Stop`/`Start` (all-false =
/// everything).
RestartScoped {
#[serde(default)]
scope: LifecycleScope,