Skip to content

fix(gateway): skip restart-safe scoped cron runs in the restart wait, keyed per profile - #131071

Merged
unsupportedpastels merged 2 commits into
NousResearch:mainfrom
unsupportedpastels:fix/130987-restart-wait-scoped-cron
Oct 2, 2026
Merged

unsupportedpastels merged 2 commits into
NousResearch:mainfrom
unsupportedpastels:fix/130987-restart-wait-scoped-cron

Conversation

@unsupportedpastels

Copy link
Copy Markdown

Problem

Fixes #130987.
Healthy cron runs already executing in an isolated systemd scope can hold the restart after-turn wait for the full cap even though they survive the gateway restart.

Fix and prior work

Preserves @Superfly73's #130988 commit via cherry-pick -x: records successful scoped handoffs, cleans up their registry, excludes them from the wait and updates the docs. Thank you for the report, scoped/degraded distinction and implementation.

Adds the profile-keyed accounting requested by @ehz0ah in review: two profiles' same-ID runs remain distinct, so a scoped or wedged run cannot hide a degraded/live sibling. The diagnosis and regression direction are credited by co-author trailer. The bare-ID accessor introduced by the source PR is replaced with disjoint keyed counts; unrelated existing bare-ID APIs remain unchanged. The observer gets the per-run restart_safe flag.

Verification

Canonical runner: tests/cron + tests/gateway: 10,520 passed, 42 skipped; main baseline: 10,515 passed, 42 skipped. No failures. The two same-ID behavioral regressions fail with source PR production restored (0 awaitable instead of 1). Real-import temporary-profile A→B→A probe reproduces the original wait on main and the collision on #130988, and passes on this branch. Ruff, Windows-footgun scan and attribution audit pass.

No live systemd restart or native Windows/macOS run was performed. Hosted CI must pass before merge.

Scope / risk

Only restart wait accounting and scoped-worker bookkeeping; no timeout/config-key, subprocess launch, interruption or durable-delivery policy changes. Degraded workers remain awaited. Not in scope: embedded Kanban drain (#103961), stop-phase timeout budget (#129957).

Superfly73 and others added 2 commits October 2, 2026 00:13
…estart wait

A cron run handed to an external worker in its own transient systemd scope
outlives the gateway: the shutdown drain deliberately leaves it unmarked
(``mark_running_jobs_interrupted``) and its final send rides the durable
delivery queue, drained by whichever gateway is live next. The after-turn
restart wait still counted it as active work, so ``/restart``, SIGUSR1 and
``hermes update`` held the gateway in ``draining`` — refusing every new turn —
for up to ``agent.restart_after_turn_timeout`` (30 min by default) while the
worker kept running regardless. Observed in the field: a 100-minute job turned
a restart into a ~30-minute lockout.

- ``cron.scheduler`` records whether an accepted handoff got its own scope
  (``dispatch.mode == "scoped"``) and exposes
  ``get_restart_safe_external_job_ids()``; runs already reported as wedged are
  excluded there too, because the gateway subtracts both counts and a run in
  both sets would be subtracted twice.
- ``_awaitable_work_count()`` subtracts that count as a second, disjoint
  exclusion; ``_describe_active_work()`` marks the unit (``restart_safe``).
- A degraded worker (external, but no reachable user bus, so it shares the
  gateway cgroup) is NOT listed and is still awaited — the restart would kill
  it mid-run.
- The wait and observation log lines now name both exclusion classes instead of
  claiming everything still listed will be interrupted.

Tests: tests/gateway/test_restart_drain.py (skip + control),
tests/cron/test_restart_safe_worker.py (registry contract).
Docs: updating.md restart section, cli-config.yaml.example.

(cherry picked from commit 6a2f0b7)
A scoped or wedged daily-brief in profile A must not hide a degraded or
live daily-brief in profile B. Split the scheduler's in-flight keys before
counting and add awaitable cron runs independently of non-cron work.
Carry the per-run restart_safe flag to the observer and preserve the
existing bare-ID accessors for unrelated callers.

Thanks to @ehz0ah for diagnosing the multiplexed collision and proposing
the profile-keyed accounting and mixed scoped/degraded regression case.
Preserve @Superfly73's source commit separately; map their verified bare
noreply email for the contributor CI gate.

Refs NousResearch#130987

Co-authored-by: z1gon <130889443+ehz0ah@users.noreply.github.com>
@alt-glitch alt-glitch added type/bug Something isn't working P1 High — major feature broken, no workaround comp/gateway Gateway runner, session dispatch, delivery comp/cron Cron scheduler and job management area/install-update Installer, updater, packaging, wheels, doctor sweeper:risk-message-delivery Sweeper risk: may drop, duplicate, misroute, or suppress messages sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades labels Oct 2, 2026

@unsupportedpastels unsupportedpastels left a comment

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @Superfly73 for the restart-safe scoped-worker fix and @ehz0ah for identifying the cross-profile collision. The source commit is preserved with cherry-pick provenance; the follow-up keeps the exclusions keyed by profile and credits the review diagnosis. Local cron/gateway suites and the main/source/salvage behavioral probe are documented in the PR. Merge only after required exact-head checks and fresh independent review pass.

@unsupportedpastels
unsupportedpastels merged commit 5bba024 into NousResearch:main Oct 2, 2026
60 checks passed
@unsupportedpastels
unsupportedpastels deleted the fix/130987-restart-wait-scoped-cron branch October 2, 2026 13:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/install-update Installer, updater, packaging, wheels, doctor comp/cron Cron scheduler and job management comp/gateway Gateway runner, session dispatch, delivery P1 High — major feature broken, no workaround sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:risk-message-delivery Sweeper risk: may drop, duplicate, misroute, or suppress messages type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

gateway: restart wait holds for cron runs that already outlive the restart (up to 30 min of refused turns)

3 participants