fix: don't fail nodes on artifact plugin sidecar exit codes - #16807
fix: don't fail nodes on artifact plugin sidecar exit codes#16807Joibel wants to merge 1 commit into
Conversation
Artifact plugin sidecars are torn down by the wait (or supervisor) container only after it has saved all outputs and logs, so an aux container that exited 0 proves every save succeeded and the sidecar's exit code carries no information about the node's outcome. The recorded code can even be a phantom: when the controller's terminateContainers kill exec races the sidecar's own clean exit, the container runtime can record a non-zero status (observed as exit code 2) for a process whose log shows it completed normally. This intermittently failed otherwise successful workflows, e.g. the artifact-passing-explicit-plugin example in CI. Ignore artifact plugin sidecar exit codes in inferFailedReason and let the existing main/wait verdict decide the node's fate. A sidecar that genuinely dies mid-save still fails the node through the aux container's failed save, and failures of main, wait/supervisor, init or user sidecars are unaffected. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018XsqqvLSrJ5sH8gN8tLbr9 Signed-off-by: Alan Clucas <alan@clucas.org>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (2)
Included review availability: Your plan provides up to 10 included reviews per hour; 9 remain after this review. 📝 WalkthroughWalkthroughThe controller now ignores artifact plugin sidecar exit codes when inferring node failure reasons. Tests cover artifact plugin exits and confirm that wait, main, and user-sidecar failures remain reported. ChangesArtifact plugin sidecar handling
Estimated code review effort: 2 (Simple) | ~10 minutes Merge Risk: ⚪ Minimal · up to This localized controller change ignores artifact-plugin sidecar exit codes while preserving failures from main, wait, and user-sidecar containers; no actionable merge-blocking risk remains after normal checks and review. Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches 💡 1🛠️ Fix failing CI checks 💡
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
make pre-commit -B(scoped:golangci-lint run workflow/controller/— only a pre-existingns_watcher.goSA1019 unrelated to this change; fullgo test ./workflow/controller/green)make feature-new) — not a featureMotivation
TestExampleWorkflows/../../examples/artifact-passing-explicit-plugin.yamlfails intermittently in CI (observed twice within two days, on both the legacy and init-less pod layouts): the workflow's pod completes successfully end to end, yet the node fails withartifact-plugin-test: Error (exit code 2).Investigation with the CI log archives and a local reproduction rig established the mechanism:
terminateContainerssweep also SIGTERMs the sidecar via akubectl exec … argoexec kill 15 1session. In both CI failures that exec completed within 6ms/80ms of the sidecar's final log line — i.e. it was in flight at the instant PID 1 exited.exit 2results in 100 attempts of file-signal teardown with kill execs spammed at the dying container, each with a byte-identical clean log andError: ""in the runtime state. No panic is involved — the wrapper genuinely exits 0.Modifications
inferFailedReasonnow ignores non-zero exit codes from artifact plugin sidecar containers (artifact-plugin-*), letting the existing main/wait verdict at the end of the function decide the node's fate. Rationale: the aux container tears these sidecars down only after all saves succeeded, so an aux container that exited 0 proves the sidecar did its job, and its exit code carries no information about the node's outcome — while demonstrably being unreliable under the exec race. This is the same position Kubernetes native sidecar containers take: their exit status does not affect pod phase.Safety is preserved by the function's existing structure: a plugin sidecar that genuinely dies mid-save fails the aux container's save, and the
wait container did not complete successfullyverdict fails the node. Failures of main, wait/supervisor, init containers, and user sidecars are unaffected (covered by tests).Both teardown mechanisms (aux file-signal and controller SIGTERM sweep) are deliberately left in place.
Verification
New table-driven
TestInferFailedReasonArtifactPluginSidecar: plugin-sidecar exit ignored (legacy wait + init-less supervisor + SIGTERM 143 variants), and negative cases proving main/wait/user-sidecar failures still fail the node with unchanged messages. The three ignore cases fail onmainand pass with the fix. Fullgo test ./workflow/controller/green.The container-runtime misattribution itself (exec racing PID 1 exit) is arguably a containerd/runc issue; a standalone docker reproducer exists and an upstream report may follow separately.
Documentation
Not needed: no user-visible behavior change beyond removing spurious failures.
AI
This PR was prepared with Claude Code (Anthropic): CI log forensics, local docker reproduction of the runtime race, fix, tests, and this description, directed and reviewed by the submitting maintainer.
🤖 Generated with Claude Code
https://claude.ai/code/session_018XsqqvLSrJ5sH8gN8tLbr9
Summary by CodeRabbit
Bug Fixes
Tests