Conversation
There was a problem hiding this comment.
🟡 Changes recommended
Interrupt races, lost periodic progress, reversible cancellation, and incomplete Windows termination reporting remain.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
Adds remote-plan pausing, resumable checkpoints, terminal cancellation, and cross-platform process-tree termination.
Changes:
- Adds pause/cancel annotation handling and checkpoint persistence.
- Extends Applyinator with interruption-aware execution and process cleanup.
- Adds comprehensive unit and end-to-end coverage.
File summaries
| File | Description |
|---|---|
go.mod |
Updates plan dependencies and Windows support. |
go.sum |
Refreshes dependency checksums. |
pkg/applyinator/applyinator.go |
Implements interruptible plan execution. |
pkg/applyinator/applyinator_test.go |
Tests interruption and process handling. |
pkg/applyinator/process_unix.go |
Manages Unix process groups. |
pkg/applyinator/process_unix_test.go |
Tests Unix process-tree termination. |
pkg/applyinator/process_windows.go |
Manages Windows Job Objects. |
pkg/k8splan/interrupt.go |
Handles pause and cancellation annotations. |
pkg/k8splan/interrupt_test.go |
Tests interrupt parsing and persistence. |
pkg/k8splan/plan_decision_test.go |
Updates canceled-state coverage. |
pkg/k8splan/plan_progress.go |
Implements resumable checkpoints. |
pkg/k8splan/plan_progress_test.go |
Tests checkpoint behavior. |
pkg/k8splan/reconcile.go |
Integrates interrupts into reconciliation. |
pkg/k8splan/secret_outcome.go |
Clears consumed checkpoints. |
pkg/k8splan/secret_outcome_test.go |
Tests checkpoint cleanup. |
pkg/k8splan/watcher.go |
Preserves checkpoints across conflicts. |
pkg/k8splan/watcher_test.go |
Tests conflict merging. |
test/e2e/suites/remote-plan/cancellation_test.go |
Adds cancellation scenarios. |
test/e2e/suites/remote-plan/failure_handling_test.go |
Tests terminal failed plans. |
test/e2e/suites/remote-plan/helpers_test.go |
Adds interruption test helpers. |
test/e2e/suites/remote-plan/pause_test.go |
Adds pause/resume scenarios. |
test/framework/secret.go |
Adds annotation and checkpoint helpers. |
test/go.mod |
Updates test-module dependencies. |
test/go.sum |
Refreshes test dependency checksums. |
test/README.md |
Documents restart coverage. |
Review details
Suppressed comments (1)
pkg/applyinator/applyinator.go:458
- A pause that arrives while the current instruction exits non-zero is assigned to
result.Interruptionhere.reconcileSecrethandles interruptions beforeOneTimeApplySucceeded, so the real instruction failure is recorded as a pause instead ofplan-state: failed, and its failure counters are lost. Pause should only stop at a successful boundary; preserve the failure when only pause is pending (while still allowing cancellation to take precedence), including the later post-periodic interruption check inApply.
// A canceled instruction may fail because its context was killed. Re-check the interrupt
// state so cancellation is reported as an interruption rather than a plan failure.
// Pause does not interrupt a running instruction, so a failure observed with pause pending
// is still a genuine instruction failure.
result.Interruption = checkInterruption(cancel, pause)
- Files reviewed: 25/27 changed files
- Comments generated: 5
- Review effort level: Balanced
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
There was a problem hiding this comment.
🟡 Changes recommended
Pause can suppress genuine failures, terminal probe conflicts can terminate the agent, and Windows termination lacks behavioral tests.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Review details
Suppressed comments (2)
Previously missed (2) — in code that hasn't changed since the last review.
pkg/applyinator/applyinator.go:469
- A pause that arrives while the current instruction is running is incorrectly treated as the cause of any later non-zero exit.
checkInterruption(cancel, pause)returnsInterruptionPaused, so reconciliation bypasses normal failure bookkeeping, records an in-progress resume checkpoint, and unpausing reruns the failed instruction without the planner resetting the failed plan. Pause is boundary-only, so a genuine instruction failure must remain a failure; only cancellation should reclassify this failed execution as an interruption.
pkg/applyinator/process_windows.go:120 - The Windows cancellation path has no executable coverage: all process-tree tests skip Windows, while only the Unix implementation has a platform-specific test (
pkg/applyinator/process_unix_test.go:19). Please add a Windows test that assigns a command which spawns a descendant, cancels it, and verifies the Job Object terminates the whole tree (plus the direct-child fallback); otherwise this critical platform-specific behavior can regress while the Windows CI remains green.
- Files reviewed: 25/27 changed files
- Comments generated: 1
- Review effort level: Balanced
There was a problem hiding this comment.
🟡 Changes recommended
Resume writes can overwrite concurrent Secret updates, and pauses can incorrectly mask genuine instruction failures.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Review details
- Files reviewed: 25/27 changed files
- Comments generated: 3
- Review effort level: Balanced
There was a problem hiding this comment.
🟡 Changes recommended
Interrupt timing can allow canceled or paused work to start, and partial cancellations may omit required warnings.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Review details
Suppressed comments (3)
Previously missed (2) — in code that hasn't changed since the last review.
pkg/applyinator/applyinator.go:783
- Using
exec.Commanddetaches process startup fromctx, while the cancellation watchdog is not armed until aftercmd.Start(). If cancellation arrives during image staging or command setup,ctxis already canceled but the command is still launched and only killed afterward. Preserve a context-aware pre-start check (without bypassing the process-tree watchdog) so canceled instructions cannot start new work.
pkg/applyinator/process_windows.go:119 - The new Windows Job Object path has no Windows-specific tests, while the process-tree cancellation tests explicitly skip Windows and only the Unix implementation gets a platform test. Add Windows coverage for successful assignment/termination, assignment fallback, and
ActiveProcessesconfirmation; otherwise the platform-specific cancellation implementation can compile yet fail at runtime unnoticed.
pkg/k8splan/reconcile.go:519
- This suppresses the required partial-application warning when cancellation kills the first instruction:
Completedcounts only successfully finished instructions, so zero does not mean the running instruction made no changes. It also suppresses warnings for a canceled periodic instruction after all one-time instructions completed. Distinguish cancellation before execution from cancellation during an apply, and emit the inconsistency warning for every in-flight cancellation that may have produced side effects.
func partialCancellationLogs(completed, total int) {
if completed <= 0 || completed >= total {
return
- Files reviewed: 25/27 changed files
- Comments generated: 1
- Review effort level: Balanced
There was a problem hiding this comment.
🔵 Needs a closer look
The change substantially alters execution, persistence, concurrency, and cross-platform process termination semantics and requires final human validation.
Review details
- Files reviewed: 25/27 changed files
- Comments generated: 0 new
- Review effort level: Balanced
7d82e87 to
cec1f31
Compare
cec1f31 to
6ee6d70
Compare
5dc5008 to
577841a
Compare
Issues:
Summary
This PR adds support for plan pause and cancellation in
system-agent's remote mode (pkg/k8splan).Operators can now suspend or cancel executing plans directly via Kubernetes Secret annotations. This enables safe plan resumption from checkpoints and grants granular control over process termination behavior.
Usage
Pause a Plan
Set
plan.cattle.io/paused = "true"on the plan Secret."false".Cancel a Plan
Set
plan.cattle.io/canceled = "true"on the plan Secret.SIGTERM/SIGKILLon Unix; Job Object termination on Windows).plan-statetopendingor recreate the Plan secret.Resume a Paused Plan
Remove the
plan.cattle.io/pausedannotation or set its value to"false".Feature Details
Annotation Handling
"true"and"false"(absent defaults to"false").canceled = "true"always takes precedence overpaused(even ifpausedcontains an invalid value). This allows operators to quickly stop runaway processes without needing to fix annotation typos first.Execution vs. Observation
MachineHealthCheckreceives accurate, up-to-date node health data even when a plan is held.Pause vs. Cancel Comparison
SIGTERMimmediately,SIGKILLafter 10s)plan-statetopending)Backward Compatibility (Checksum Flow)
For legacy orchestrators operating without
plan-statesupport:Tests Added
Unit Tests
interrupt_test.go: Annotation parsing, interrupt state resolution, precedence rules, polling logic, and edge cases.plan_progress_test.go: Checkpoint parsing/marshaling, resume state resolution, and sanitization.suppression_test.go: Matrix of annotation combinations and their impacts on reconciliation.reconcile_test.go(expanded):plan-statetransitions, checkpoint updates, and interrupt handling during application.applyinator_test.go(expanded): Interruption channels, resume-from behaviors, and probe execution while on hold.process_unix_test.go: Process group termination, signal handling, and zombie reaping.process_windows_test.go: Job Object termination boundaries and edge cases.Integration & E2E Tests
cancellation_test.go: Full-lifecycle cancellation workflows.pause_test.go: Pause, resume, and edge-case execution sequences.helpers_test.go: Framework helpers for annotation manipulation.Note that E2E Tests for Windows will be added in the rancher/wins repo. See rancher/wins#565
Known Limitations
pkg/localplan): Pause and cancel capabilities require the remote modeplan-stateflow. Local plans remain checksum-only without annotation support.setsid()escape process group signals and confirmation checks (cgroups are required to fully bridge this gap). ATerminationIncompleteflag is populated when this condition is detected to alert operators.Verification & Testing Instructions
Run the full test suite: