Repository navigation
Hold an engine Deployment unready until its rollout finishes - #570
Draft
dennis-upbound wants to merge 1 commit into
Draft
dennis-upbound wants to merge 1 commit into
dennis-upbound wants to merge 1 commit into
Conversation
|
Docs preview: https://modelplane-docs-pr-570.vercel.app (ready once the site's Content workflow finishes) |
A replica reported Ready while its engine's Deployment was partway through a rolling update. The Deployment's readiness query required Available and a ready pod per copy, but readyReplicas also counts pods from the previous ReplicaSet. With the default maxSurge, a one-copy engine kept its old pod ready while the new one started. The query held, so the replica, its endpoint and its deployment all reported Ready though no copy ran the current spec. The query could also pass on the status provider-kubernetes reads back when it applies a spec change, before the Deployment controller has processed that change. The Deployment's query now also requires status.observedGeneration to match metadata.generation, updatedReplicas to reach spec.replicas, and status.replicas to equal updatedReplicas. These are the checks kubectl rollout status makes. During a rollout the replica keeps serving from its old copies and reports ModelReady False with reason RollingOut. Its deployment reports ReplicasServing True and Ready False until the rollout finishes. The LeaderWorkerSet query doesn't change. lws sets Available only once every group is ready and updated, and sets it False while it replaces a group. lws doesn't publish an observedGeneration, so the query can't reject a status read back before the lws controller processes a template change. The shared Available query now checks that status exists, as the other functions' queries do. Without that check cel-go fails with "no such key: status" on a workload that has no status yet, where the query should return false. Fixes modelplaneai#497. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Dennis Ramdass <dennis@upbound.io>
dennis-upbound
force-pushed
the
dennis/ready-after-rollout
branch
from
October 26, 2026 20:04
c841ef8 to
c4387e2
Compare
This branch has not been deployed
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.
Description of your changes
Fixes #497.
#562 made an engine's workload Object wait for a ready pod or group per copy, and watched it, which covers the
maxSurge: 0case in the issue and the stale status in its comments. A Deployment could still read ready partway through a rolling update.readyReplicasalso counts pods from the previous ReplicaSet, so with the defaultmaxSurgea one-copy engine kept its old pod ready while the new pod started, and the replica, endpoint and deployment all reported Ready though no copy ran the current spec. The query could also pass on the status provider-kubernetes reads back when it applies a spec change, before the Deployment controller has processed that change.The Deployment's readiness query now also requires
status.observedGenerationto matchmetadata.generation,updatedReplicasto reachspec.replicas, andstatus.replicasto equalupdatedReplicas. These are the checkskubectl rollout statusmakes. During a rollout the replica keeps serving from its old copies and reportsModelReady=Falsewith reasonRollingOut, so ModelServing doesn't drop. Its ModelDeployment reportsReplicasServing=TrueandReady=Falseuntil the rollout finishes, with reasonDegraded, as it already did for a LeaderWorkerSet rollout. The status docs now say a serving deployment that isn't Ready may be rolling out.The LeaderWorkerSet query doesn't change. lws v0.8.0 sets
Availableonly once every group is ready and runs the current template, and sets it False while it replaces a group (controller). lws doesn't publish anobservedGeneration. Grove's queries don't change either: RollingRecreate deletes a copy before it recreates it, so the scaling group'savailableReplicasdrops during the update.The shared
Availablequery now checks thatstatusexists, as the other functions' queries do. Without that check cel-go fails withno such key: statuson a workload that has no status yet, where the query should return false.I evaluated the queries with cel-go v0.30.0 in the environment provider-kubernetes v1.4.1 uses, against Deployment and LeaderWorkerSet status for steady state, a surge rollout, a
maxSurge: 0rollout, a fresh create, N-1 of N copies ready, a staleobservedGeneration, a stalled surge, and a strategy-only change. The old query passed on the surge rollout, on a two-copymaxSurge: 0rollout between copies, and on the stale generation. The new one passes only in steady state and while scaling down.On upgrade the readiness query changes on every engine's and endpoint picker's Object, and no pod restarts. A workload in steady state passes the old and new queries. A Ready replica doesn't change. A replica whose rollout has stalled with its old pod serving, such as a surge pod that can't get a device on a full pool, turns
Ready=Falsewith reasonRollingOutand keeps serving.#572 changes the same Deployment's
strategy. This PR and #572 merge cleanly, and the merged tests pass. A strategy-only change bumps the Deployment's generation without starting a new ReplicaSet, and this query reads not Ready until the Deployment controller observes it. #572 changes the strategy when copies go down, while the replica is already not Ready, and again when they come back. That second change can turn a replica that just became Ready back toRollingOutfor one status update from the Deployment controller. ModelServing doesn't drop.Decisions:
Degradedduring a rollout. ItsReadyreports full capacity across replicas, and a replica mid-rollout isn't at full capacity. Each replica's ownModelReadysaysRollingOut. A deployment-levelRollingOutreason can follow once the deployment aggregates its replicas' reasons, as ModelDeployment status doesn't say why a model isn't serving #498 designs.Ready=Falseon upgrade by design. ModelDeployment and ModelEndpoint report Ready while the engine has no ready pods #497 asks thatReadymean every copy runs the current spec.ModelServingdoesn't change, and neither does routing.observedGeneration.I have:
nix flake check(or./nix.sh flake check) and made sure it passes.git commit -s.🤖 Generated with Claude Code