Skip to content

Commit e6796dd

Browse files
authored
Merge pull request #402 from NVIDIA/jobs-migration/373-timeout-retry
feat(operator): treat a stage timeout as a retryable failure (#373)
2 parents 15a317f + d86c27c commit e6796dd

23 files changed

Lines changed: 817 additions & 175 deletions

chart/RELEASE_NOTES.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,21 @@ For the full commit-level log see CHANGELOG.md.
55

66
## Unreleased
77

8+
### New Features
9+
10+
- **Package stage execution moved to `batch/v1` Jobs**, with four new operator
11+
env values under `controllerManager.manager.env`:
12+
13+
| Value | Default | What it does |
14+
| --- | --- | --- |
15+
| `jobStageTimeout` | `"1h"` | Default per-attempt deadline for a package stage, when the package sets no `stageTimeout` of its own. `"0"` removes the time bound. |
16+
| `jobBackoffLimit` | `"3"` | Retries after the first attempt before a stage is surfaced as `erroring` — so at most four attempts. |
17+
| `jobTtlSucceeded` | `"1h"` | How long a succeeded stage Job (and its logs) is kept. Minimum `"1m"`. |
18+
| `jobTtlFailed` | `"24h"` | How long a failed stage Job is kept, so failure logs outlive success logs. Minimum `"1m"`. |
19+
20+
The chart also gains `batch/job` RBAC for the operator; no values change is
21+
required to upgrade.
22+
823
### Bug Fixes
924

1025
- **Helm upgrade no longer fails on the immutable Deployment selector after the
@@ -32,6 +47,12 @@ For the full commit-level log see CHANGELOG.md.
3247

3348
### Upgrade notes
3449

50+
- **A crash-looping package now gives up after ~70 seconds instead of retrying
51+
for up to an hour.** `jobBackoffLimit` bounds retries per stage; if you rely on
52+
a package self-healing through transient environment problems, raise it before
53+
upgrading. See the operator release notes for the full behavior change.
54+
- **`jobTtlSucceeded` / `jobTtlFailed` must be at least `"1m"`.** Setting `"0"`
55+
to disable retention makes the operator fail validation at startup.
3556
- No action is required: the selector-migration hook runs automatically on
3657
`helm upgrade` and only recreates the Deployment when its selector is stale.
3758
To perform the recreate manually instead, set `selectorMigration.enabled=false`

chart/templates/deployment.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,8 @@ spec:
101101
value: {{ quote .Values.controllerManager.manager.env.jobTtlFailed }}
102102
- name: JOB_STAGE_TIMEOUT
103103
value: {{ quote .Values.controllerManager.manager.env.jobStageTimeout }}
104+
- name: JOB_BACKOFF_LIMIT
105+
value: {{ quote .Values.controllerManager.manager.env.jobBackoffLimit }}
104106
- name: RUNTIME_REQUIRED_TAINT
105107
value: {{ quote .Values.controllerManager.manager.env.runtimeRequiredTaint }}
106108
- name: PAUSE_IMAGE

chart/templates/nodewright-crd.yaml

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -526,10 +526,24 @@ spec:
526526
type: object
527527
stageTimeout:
528528
description: |-
529-
StageTimeout bounds the wall-clock runtime of each of this package's stage Jobs
530-
(mapped to the Job's activeDeadlineSeconds), all retries and reboot time included.
531-
A stage that runs past it is failed and surfaced as erroring. Unset uses the
532-
operator default (JOB_STAGE_TIMEOUT); "0" disables the deadline for this package.
529+
StageTimeout bounds the wall-clock runtime of one attempt at each of this package's
530+
stages (the stage Job pod's activeDeadlineSeconds). An attempt that runs past it is
531+
killed and retried like any other failed attempt, and the package surfaces as erroring
532+
once the operator's retry budget (JOB_BACKOFF_LIMIT) is spent. Interrupt stages are the
533+
exception: their attempt must span a reboot, so it bounds the whole stage instead.
534+
Unset uses the operator default (JOB_STAGE_TIMEOUT); "0" removes the time bound for this
535+
package, leaving the retry budget as its only limit. Note what that does NOT bound: the
536+
budget is only spent by attempts that fail, so with "0" an attempt that hangs hangs
537+
forever. There is also no bound on a pod the kubelet never acknowledges — the attempt clock
538+
runs from the pod's start time, which such a pod never gets — so that case is unbounded at
539+
any stageTimeout. It surfaces as a stage stuck in_progress with a Pending pod, and is node
540+
health rather than stage health.
541+
542+
The value is fixed when a stage's Job is created. Editing it does not change a Job already
543+
running, because the bound lives on that Job's pod template and a Job's template is
544+
immutable. To apply a new value to work already under way, clear that Job — `kubectl
545+
nodewright package rerun <package>`, or deleting the Job directly — and the stage restarts
546+
under the new value. Otherwise it takes effect at the package's next stage.
533547
type: string
534548
uninstall:
535549
description: Uninstall configures explicit uninstall support

chart/values.yaml

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,9 +85,23 @@ controllerManager:
8585
## Jobs by outcome, so failure logs outlive success logs.
8686
jobTtlSucceeded: "1h"
8787
jobTtlFailed: "24h"
88-
## jobStageTimeout is the default activeDeadlineSeconds for a package stage Job when the
89-
## package itself sets no stageTimeout. "0" disables the deadline.
88+
## jobStageTimeout is the default per-attempt deadline for a package stage Job when the
89+
## package itself sets no stageTimeout. "0" removes the time bound, leaving jobBackoffLimit
90+
## as the only limit — and a retry budget is only spent by attempts that FAIL, so with "0"
91+
## an attempt that hangs hangs forever. A pod the kubelet never acknowledges is unbounded at
92+
## any value, since the per-attempt clock starts from the pod's start time; that shows up as
93+
## a stage stuck in_progress with a Pending pod, and is node health rather than stage health.
94+
## Like jobBackoffLimit below, this is fixed when a stage's Job is created: changing it does
95+
## not affect Jobs already running. Clear those Jobs (`kubectl nodewright package rerun`) to
96+
## apply a new value to work already under way.
9097
jobStageTimeout: "1h"
98+
## jobBackoffLimit is how many retries a package stage gets after its first attempt before
99+
## its Job goes terminal — so a stage runs at most jobBackoffLimit+1 times. If a retained
100+
## attempt genuinely failed the stage then parks as erroring, awaiting a rerun/reset/config
101+
## change; otherwise it simply re-runs. It bounds every failure class, not just timeouts,
102+
## so raising it buys a crash-looping package more time to self-heal. "0" gives a stage a
103+
## single attempt with no retry.
104+
jobBackoffLimit: "3"
91105
## runtimeRequiredTaint: This feature assumes nodes are added to the cluster with `--register-with-taints` kubelet flag.
92106
## This taint is assume to be all new nodes, and skyhook pods will tolerate this taint, and remove it one the nodes packages are complete.
93107
## NOTE: If your systems nodes have this taint make sure to add the toleration to the controllerManager.tolerations

0 commit comments

Comments
 (0)