Repository navigation
[9.4] (backport #15423) Give service-runtime components more time to check in before failing an upgrade - #15863
Merged
Merged
Conversation
…an upgrade (#15423) * Give service-runtime components more time to check in before failing an upgrade Elastic Defend restarting slowly after an upgrade could be mistaken for a broken Agent build and trigger an unnecessary rollback. The FAILED threshold for service-runtime components is now derived from their own configured install/uninstall/check timeouts instead of the generic 90s window; DEGRADED reporting cadence is unchanged. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Cap service check-in failure window to a safe margin below the upgrade watcher grace period A service-runtime component's failure threshold could still exceed a very short configured grace period, and the grace period value was captured once at startup so a live config reload never reached already-running components. Cap the threshold relative to the grace period and share it live between the Manager and its components so a reload takes effect immediately. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Simplify grace period wiring: drop ManagerOption in favor of a plain setter The grace period is a mutable, post-construction value now that Reload can update it live, so threading it through a functional-options mechanism at construction time added an abstraction the value did not need. A plain SetServiceCheckinGracePeriod method called once after NewManager achieves the same result with less API surface. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Declare Reload on the RuntimeManager interface instead of type-asserting RuntimeManager was the only reloadable subsystem in Coordinator.generateAST without a Reload method on its own interface, so reloading it required a type assertion to the concrete *runtime.Manager. Add Reload to the interface itself, matching UpgradeManager and MonitorManager, and give the test fake a no-op implementation. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Trim comments that leaked implementation detail Several comments walked through how the grace period sharing/atomics work instead of just stating what each piece is for. Shortened them to plain, purpose-focused descriptions. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Drop remaining method-name reference from a comment The field comment still named Reload as the update mechanism, which the gracePeriodValue type comment already covers. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Drop redundant live-update note from a field comment The gracePeriodValue type comment already explains that the value can be updated live, so restating it on every field that holds one was redundant. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Add Reload to the generated RuntimeManager mock Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * Regenerate RuntimeManager mock via mockery and add it to .mockery.yaml Adds the coordinator's RuntimeManager interface to .mockery.yaml so it is regenerated automatically going forward. Runs mockery v3 to produce the updated mock (includes the new Reload method) and picks up minor v3-format header updates across other mocks in the same run. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * Pin service check-in grace period to upgrade marker during active upgrade Stores the configured watcher grace period in the upgrade marker when an upgrade starts. The new agent reads it back and uses it as a ceiling on the check-in miss cap, so a Fleet config reload that increases the grace period mid-upgrade cannot push component failure detection past the deadline the watcher already committed to. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * Assign upgradeGracePeriod to a variable in NewUpgrader Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * Simplify grace period handling: plain field on Manager, skip Reload during upgrade gracePeriodValue goes back to a simple atomic with no ceiling. Manager gains a plain upgradeGracePeriod field that is set once from the marker at startup. Reload skips updating the grace period while an upgrade is active — the marker value is a constant for this upgrade and live config changes are irrelevant. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * Lift upgrade grace period freeze when upgrade reaches terminal state Elastic Defend can take longer than the hardcoded ~90 s window to restart, causing the upgrade watcher to roll back a healthy upgrade. This commit introduces a grace-period freeze so the runtime uses the same window configured in the upgrade watcher for the duration of an upgrade. Changes: - gracePeriodValue on Manager holds both a live value (updated by Reload) and an upgrade value (frozen when an upgrade starts, cleared on completion). Get() returns the upgrade value while non-zero. - IsUpgradeActive() on UpdateMarker encapsulates the three conditions (not acked, GracePeriod > 0, non-terminal) used at startup to decide whether to activate the freeze. - Coordinator clears the freeze via ClearUpgradeGracePeriod when the upgradeMarkerUpdate channel delivers a terminal or nil-Details marker. - MockRuntimeManager regenerated to include ClearUpgradeGracePeriod. - Tests: TestManagerGracePeriodUpgradeFreeze, TestUpdateMarkerIsUpgradeActive, TestCoordinatorClearUpgradeGracePeriodOnMarkerUpdate. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * Remove upgrade marker grace period freeze mechanism The freeze mechanism (snapshot GracePeriod in the marker, freeze the service check-in window during active upgrades) was added to prevent a config reload from shortening the window mid-upgrade. In practice the grace period is never user-configurable at runtime, so the problem it solved does not exist. Remove: UpdateMarker.GracePeriod field and serializer counterpart, IsUpgradeActive(), gracePeriodValue type and its atomic fields, the three Manager methods (SetServiceCheckinGracePeriod, SetUpgradeGracePeriod, ClearUpgradeGracePeriod), ClearUpgradeGracePeriod from RuntimeManager interface, the coordinator handler that called it, and all associated tests. Simplify: maxCheckinMisses no longer takes a dynamic cap from the manager; checkinFailureTimeout drops the uninstall operation (only install/check determine the initial startup window). Bump defaultGracePeriodDuration to 11m so it always exceeds the 10m Elastic Defend operation timeout, and add TestUpgradeGracePeriodExceedsMaxServiceTimeout to enforce that relationship. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * Drop Reload from RuntimeManager; strengthen grace period constraint test Remove the no-op Reload method from RuntimeManager interface, Manager, the mock, and fakeRuntimeManager — it was left over from the abandoned freeze mechanism and never needed. Make TestUpgradeGracePeriodExceedsMaxServiceTimeout load the real endpoint-security.spec.yml so a spec change that breaks the grace period invariant fails the test rather than passing against a hardcoded constant. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com> (cherry picked from commit eb3502f)
mergify
Bot
requested review from
lorienhu and
samuelvl
and removed request for
a team
July 28, 2026 12:13
|
Pinging @elastic/elastic-agent-control-plane (Team:Elastic-Agent-Control-Plane) |
5 tasks done
💚 Build Succeeded
cc @macdewee |
macdewee
enabled auto-merge (squash)
July 28, 2026 14:47
macdewee
approved these changes
Jul 28, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What does this PR do?
Changes check-in behavior for the services we don't have control over, like Elastic Defend. Computes the number of missed check-ins to allow based on their own startup time as much as possible, limited by the upgrade watcher's grace period with some margin, so we do not fail prematurely. Always uses the live-reloaded grace period configuration, so a config change takes effect without restarting Agent.
Why is it important?
Elastic Defend sometimes takes longer than 90 seconds to fully restart after an Agent upgrade, even when nothing is wrong. Agent was treating that normal slow restart as a broken upgrade and automatically rolling it back. This caused unnecessary rollbacks, and customers were working around it by removing Defend before upgrading and re-adding it afterward.
Waiting longer only helps if a truly broken component still gets caught before the upgrade watcher gives up. That's why the wait is capped below the watcher's grace period, and why that cap updates live if the grace period setting changes.
Checklist
I have made corresponding changes to the documentationI have made corresponding change to the default configuration files./changelog/fragmentsusing the changelog toolI have added an integration test or an E2E testDisruptive User Impact
None expected. Service-managed components (currently only Elastic Defend) get more time before being marked failed, but only up to their own configured operation timeouts and always below the upgrade watcher's grace period. Components that are genuinely stuck still end up failed, just later. Changing the grace period setting now takes effect immediately, without restarting Agent.
How to test this PR locally
Run
go test ./pkg/component/runtime/... -run "TestService|TestManagerReload" -vto see the new unit tests covering: a normal check-in staying healthy, a slow-but-within-timeout check-in staying degraded instead of failed, a genuinely stuck component still ending up failed, a component with no configured timeout keeping the old 90 second behavior, the wait staying capped below the grace period, and the grace period updating live on a config reload.Related issues
This is an automatic backport of pull request #15423 done by [Mergify](https://mergify.com).