fix(task): replace-pod judges staleness per pod, not by equal StatefulSet revisions - #564
Conversation
…isions Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
🤖 Devin AI EngineerI'll be helping with this pull request! Here's what you should know: ✅ I will automatically:
Note: I can only respond to comments from users who have write access to this repository. ⚙️ Control Options:
|
PR SummaryMedium Risk Overview Pod deletion now uses a UID precondition on delete and treats Conflict like NotFound so a stale cache entry cannot delete a recreated pod with the same name. Adds Reviewed by Cursor Bugbot for commit 29b3140. Bugbot is set up for automated code reviews on this repo. Configure here. |
There was a problem hiding this comment.
Drops replace-pod's CurrentRevision == UpdateRevision short-circuit so pod staleness is judged per pod against UpdateRevision, fixing the rollback shape where equal revisions hid a pod still running an abandoned revision, and adds a test for it. The logic is correct — the per-pod loop still no-ops the already-rolled case and the recreated pod lands at UpdateRevision under OnDelete, so nothing blocks; codex's diff-only reading reported no findings and contributed none to carry.
Non-blocking
1 finding on the changed lines, as inline comments.
- internal/controller/seinetwork/envtest/sts_status_faker.go documents its
updateRevision == currentRevisionstub as being "so ReplacePod's 'rollout complete' branch fires immediately" — that branch no longer exists. Behaviour in envtest is unchanged (no pods carry a revision hash there, so the loop completes anyway), but the comment now explains a rationale the code has dropped.
1 nit, not posted on the code
internal/task/replace_pod.go:73— The removed short-circuit also sat in front of this guard, so an already-rolled StatefulSet with no selector or replicas > 1 used to complete as a no-op and now returns a Terminal error that fails the plan. Self-healing in practice (the controller re-applies replicas=1), andTestReplacePod_MultiReplica_TerminalErroronly covers the unequal-revision shape.
seidroid review · decision approve · session 682bdab9954749d2bcc3803060767165 · turn resp_claude_e776fd65a912cf0b3bf3d89a825bc899 · item 368a6b6b46fb5040bede24c1da9eb7bd
Findings: 0 blocking | 2 non-blocking | 1 posted inline
…mment Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Summary
replace-podshort-circuited to complete whensts.Status.CurrentRevision == sts.Status.UpdateRevision, without looking at the pods. On an image rollback that wedged the NodeUpdate plan: the StatefulSet controller resolves a rollback to a revision still in history by pointingUpdateRevisionback at it, soCurrentRevision == UpdateRevisionwhile the (OnDelete) pod still runs the abandoned revision.replace-podcompleted without deleting anything andobserve-imagethen waited forever for a replacement that was never triggered — recovery required manually deleting pods (seen today onbrandon-evmonly-400msafter harbor-engineering-workspace#267 reverted #266).if sts.Status.UpdateRevision == "" { return nil } - if sts.Status.CurrentRevision == sts.Status.UpdateRevision { - e.complete() - return nil - }The per-pod loop already skips pods whose
controller-revision-hashequalsUpdateRevision, so the already-rolled case is still a no-op (TestReplacePod_AlreadyAtUpdateRevision_NoOpunchanged). AddedTestReplacePod_RollbackWithEqualRevisions_DeletesStalePodfor the rollback shape (current == update == rev-a, pod atrev-b).Link to Devin session: https://app.devin.ai/sessions/15fbcb9794c54a48a182b0b29c017d7e
Open in Devin Desktop: https://app.devin.ai/desktop/session/15fbcb9794c54a48a182b0b29c017d7e?variant=devin
Requested by: @philipsu522