feat(api): Add terminationGracePeriodSeconds to PodSpecPatch in TrainJob#3324
Conversation
|
🎉 Welcome to the Kubeflow Trainer! 🎉 Thanks for opening your first PR! We're happy to have you as part of our community 🚀 Here's what happens next:
Join the community:
Feel free to ask questions in the comments if you need any help or clarification! |
5d3b20c to
73143f5
Compare
There was a problem hiding this comment.
Pull request overview
This PR extends the TrainJob RuntimePatches API to allow per-TrainJob overrides of terminationGracePeriodSeconds via PodSpecPatch, enabling longer graceful shutdowns for workloads like PyTorch Elastic that need time to checkpoint on SIGTERM.
Changes:
- Add
TerminationGracePeriodSeconds *int64(Minimum=0) toPodSpecPatchand propagate it through generated Go/OpenAPI/CRD artifacts. - Update the Python client model to include
terminationGracePeriodSeconds. - Add integration + webhook coverage to validate schema enforcement and verify the field propagates into JobSet pod specs.
Reviewed changes
Copilot reviewed 9 out of 9 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
pkg/apis/trainer/v1alpha1/trainjob_types.go |
Adds the new PodSpecPatch field with kubebuilder minimum validation. |
manifests/base/crds/trainer.kubeflow.org_trainjobs.yaml |
Exposes the field in the TrainJob CRD schema (min 0). |
pkg/client/applyconfiguration/trainer/v1alpha1/podspecpatch.go |
Extends server-side apply configuration with a WithTerminationGracePeriodSeconds builder. |
pkg/apis/trainer/v1alpha1/zz_generated.deepcopy.go |
Regenerates deepcopy logic to include the new pointer field. |
pkg/apis/trainer/v1alpha1/zz_generated.openapi.go |
Regenerates OpenAPI schema to include the new field. |
api/python_api/kubeflow_trainer_api/models/trainer_v1alpha1_pod_spec_patch.py |
Updates the Python client model to support the new field. |
pkg/util/testing/wrapper.go |
Adds a JobSetWrapper helper to set terminationGracePeriodSeconds in expected JobSet pod specs. |
test/integration/webhooks/trainjob_test.go |
Adds webhook validation tests for valid and invalid (negative) values. |
test/integration/controller/trainjob_controller_test.go |
Adds integration coverage ensuring the patch propagates into the created JobSet pod specs. |
8a3aa76 to
6095a15
Compare
There was a problem hiding this comment.
Thanks @krishdef7, the API changes look good.
/assign @tenzen-y @astefanutti @efazal @kaisoz
| // terminationGracePeriodSeconds patches the termination grace period for Pods | ||
| // in the target job templates. This allows users to configure sufficient time | ||
| // for checkpoint saving on TrainJob completion or node drain. | ||
| // +kubebuilder:validation:Minimum=0 |
There was a problem hiding this comment.
Keeping minimum: 0, Kubernetes itself treats 0 as a valid value meaning immediate termination via SIGKILL with no grace period. Setting minimum: 1 would prevent users from disabling the grace period entirely, which is a valid use case (e.g. forcing immediate pod termination on drain).
|
@andreyvelich: GitHub didn't allow me to assign the following users: efazal. Note that only kubeflow members with read permissions, repo collaborators and people who have commented on this issue/PR can be assigned. Additionally, issues/PRs can only have 10 assignees at the same time. DetailsIn response to this:
Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository. |
| // in the target job templates. This allows users to configure sufficient time | ||
| // for checkpoint saving on TrainJob completion or node drain. | ||
| // +kubebuilder:validation:Minimum=0 | ||
| // +optional |
There was a problem hiding this comment.
Should this field be immutable too?
There was a problem hiding this comment.
Added immutability via +kubebuilder:validation:XValidation:rule="self == oldSelf" consistent with other PodSpecPatch fields like serviceAccountName. Also added a webhook integration test ("Should fail to update TrainJob terminationGracePeriodSeconds after creation") to verify the update is rejected.
andreyvelich
left a comment
There was a problem hiding this comment.
Thanks for this contribution! The implementation looks solid — correct type, appropriate validation, and good test coverage. Review performed with AI tools.
| // for checkpoint saving on TrainJob completion or node drain. | ||
| // +kubebuilder:validation:Minimum=0 | ||
| // +optional | ||
| TerminationGracePeriodSeconds *int64 `json:"terminationGracePeriodSeconds,omitempty"` |
There was a problem hiding this comment.
Suggestion: Consider adding terminationGracePeriodSeconds to the existing unit test in pkg/runtime/core/trainingruntime_test.go (the "succeeded to build JobSet with TrainJob's RuntimePatches" test case around line 191) alongside the other PodSpecPatch fields tested there (ServiceAccountName, Tolerations, etc.). This would provide faster regression detection at the unit level without needing the full integration environment.
There was a problem hiding this comment.
Done, added TerminationGracePeriodSeconds: ptr.To(int64(300)) to the input patch and TerminationGracePeriodSeconds(constants.Node, 300) to the expected output in the "succeeded to build JobSet with TrainJob's RuntimePatches" test case.
| Obj() | ||
| }, | ||
| testingutil.BeInvalidError()), | ||
| ) |
There was a problem hiding this comment.
Suggestion: Consider adding a boundary test for ptr.To(int64(0)) with gomega.Succeed(). Zero is a valid value per the CRD (minimum: 0) but has special Kubernetes semantics (immediate termination with no grace period). Testing this boundary documents the intent and guards against accidental Minimum=1 refactors.
There was a problem hiding this comment.
Done, added "Should succeed to create TrainJob with zero terminationGracePeriodSeconds" entry with ptr.To(int64(0)) and gomega.Succeed().
| description: |- | ||
| terminationGracePeriodSeconds patches the termination grace period for Pods | ||
| in the target job templates. This allows users to configure sufficient time | ||
| for checkpoint saving on TrainJob completion or node drain. |
There was a problem hiding this comment.
IMO this description should be more generic and follow the convention set by the other PodSpecPatch fields, so there's no need to have a use case example here
There was a problem hiding this comment.
@krishdef7 Are you still working on this PR? Or we can find a new contributors to finish it?
There was a problem hiding this comment.
Updated, removed the use-case example from the description, now reads: "terminationGracePeriodSeconds patches the termination grace period for Pods in the target job templates."
|
would it make sense to delegate WDYT @andreyvelich ? |
I think, we have discussion about it here: kubernetes-sigs/jobset#1211 (comment) |
6dc5d79 to
0516d95
Compare
Adds terminationGracePeriodSeconds field to PodSpecPatch so users can configure pod termination grace period per TrainJob via RuntimePatches. This is needed for distributed training with PyTorch Elastic (torchrun) where large models (70B+ parameters) require more than the default 30s to complete JIT checkpointing before SIGKILL on node drain or TrainJob pause. No changes to merge logic in trainingruntime.go are required since the existing StrategicMergePatch applied at batchv1.JobTemplateSpec level already handles this field automatically. Closes kubeflow#3285 Signed-off-by: krishdef7 <[email protected]>
0516d95 to
5ab2b1e
Compare
|
@kaisoz @andreyvelich @astefanutti @tenzen-y, all comments are addressed, the CRD description is now generic, the immutability XValidation rule is in place, the boundary test for |
|
/lgtm All the comments were addressed and I agree on keeping the minimum set to 0 (reason). I'll leave it to @andreyvelich for the final approval |
andreyvelich
left a comment
There was a problem hiding this comment.
Thanks for this @krishdef7!
/lgtm
/approve
/hold
/assign @astefanutti @akshaychitneni @robert-bell @tenzen-y in case you have any followup questions.
|
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: andreyvelich The full list of commands accepted by this bot can be found here. The pull request process is described here DetailsNeeds approval from an approver in each of these files:
Approvers can indicate their approval by writing |
|
@robert-bell: changing LGTM is restricted to collaborators DetailsIn response to this: Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository. |
|
/hold cancel |
What this PR does / why we need it
Adds
terminationGracePeriodSecondstoPodSpecPatchso users can configure pod termination grace period per TrainJob viaRuntimePatches, without requiring cluster-admin access to modify the TrainingRuntime.This is needed for distributed training with PyTorch Elastic (
torchrun). When a TrainJob is paused or a node is drained, Kubelet sends SIGTERM to the pod. The TorchElastic agent propagates this to worker processes, which perform JIT checkpointing before shutdown. For large models (70B+ parameters), the default 30-second grace period is insufficient to complete checkpoint saves to disk or remote storage (S3/PVC).Users need to set
terminationGracePeriodSecondsalongsideTORCH_ELASTIC_SHUTDOWN_TIMEOUT(configurable since pytorch/pytorch#172596) to give workers enough time to save state before SIGKILL.Previously, this field could only be set in the TrainingRuntime template, affecting all jobs using that runtime. This PR exposes it as a per-TrainJob override consistent with other
PodSpecPatchfields likenodeSelectorandtolerations.No changes to merge logic in
trainingruntime.goare required — the existingStrategicMergePatchapplied atbatchv1.JobTemplateSpeclevel already handles this field automatically.Which issue(s) this PR fixes
Fixes #3285
Changes
TerminationGracePeriodSeconds *int64toPodSpecPatchwith// +kubebuilder:validation:Minimum=0markerzz_generated.deepcopy.go,zz_generated.openapi.go,podspecpatch.goapplyconfiguration, Python client model, and CRDTerminationGracePeriodSecondshelper toJobSetWrapperin test utilitiesChecklist