Skip to content

Fixing pod leak in KubernetesJobOperator#1

Merged
jykae merged 13 commits into
mainfrom
copilot/fix-kubernetesjoboperator-pod-leak
May 22, 2026
Merged

Fixing pod leak in KubernetesJobOperator#1
jykae merged 13 commits into
mainfrom
copilot/fix-kubernetesjoboperator-pod-leak

Conversation

Copy link
Copy Markdown

Copilot AI commented May 22, 2026

  • Inspect unresolved review comments and affected docs/newsfragment text
  • Update KubernetesJobOperator docs for on_finish_action and on_kill_action behavior
  • Update newsfragment wording to match actual supported actions/kill behavior
  • Run targeted validation for touched docs files
  • Run final validation checks and summarize

Copilot AI added 2 commits May 22, 2026 11:10
…sJobOperator

KubernetesJobOperator inherited from KubernetesPodOperator but overrode
execute() without calling post_complete_action(), so the monitoring /
log-streaming pods discovered via get_pods() were never deleted. These
pods have no ownerReferences to the V1Job, so ttl_seconds_after_finished
and the Foreground cascade in on_kill don't reap them either.

- execute() and execute_complete() now wrap their work in try/finally and
  call post_complete_action() for each pod in self.pods. on_finish_action
  (delete_pod / delete_succeeded_pod / keep_pod) is now honoured.
- on_kill() additionally calls pod_manager.delete_pod() for each
  monitoring pod (the Job's foreground cascade doesn't reach them).
- Per-pod cleanup errors are logged but never mask the in-flight
  exception, so Job-level failures keep propagating.
- execute_complete() resolves monitoring pods once and shares the lookup
  between the log-retrieval path and the cleanup path.
- Added unit tests, a bugfix newsfragment, and an operators.rst section
  documenting the cleanup contract.
… drop unused import, relax pod-deletion ordering in test, fix trailing comma
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR addresses a resource-leak in KubernetesJobOperator by ensuring the monitoring/log-streaming pods discovered via get_pods() are cleaned up at the end of execution (including kill and deferrable-resume paths), and documents how on_finish_action applies to these pods.

Changes:

  • Add monitoring-pod cleanup to execute() (via finally), execute_complete(), and on_kill().
  • Add unit tests covering cleanup on success/failure, honoring on_finish_action, deferrable resume cleanup, and kill-path cleanup.
  • Document the distinction between Job-owned worker pods vs. operator-created monitoring pods, and add a bugfix newsfragment.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.

File Description
providers/cncf/kubernetes/src/airflow/providers/cncf/kubernetes/operators/job.py Adds cleanup logic for monitoring pods across success/failure/kill/deferrable resume paths.
providers/cncf/kubernetes/tests/unit/cncf/kubernetes/operators/test_job.py Adds regression tests asserting monitoring-pod cleanup behavior and on_finish_action handling.
providers/cncf/kubernetes/newsfragments/kubernetes-job-operator-cleanup-monitoring-pods.bugfix.rst Release note describing the monitoring-pod leak fix and new behavior.
providers/cncf/kubernetes/docs/operators.rst Documentation explaining monitoring pods and how on_finish_action affects their cleanup.

Comment thread providers/cncf/kubernetes/src/airflow/providers/cncf/kubernetes/operators/job.py Outdated
Comment thread providers/cncf/kubernetes/tests/unit/cncf/kubernetes/operators/test_job.py Outdated
In _cleanup_monitoring_pods, remote_pod is resolved via find_pod(), which is designed to locate a single matching pod by task-instance labels and can invoke duplicate-pod resolution logic (process_duplicate_label_pods). For KubernetesJobOperator with parallelism > 1, this lookup can return the wrong pod (or trigger duplicate-handling side effects), so post_complete_action() may receive a mismatched remote_pod. Consider using the already-discovered pod’s name/namespace to refresh state (e.g. via hook.get_pod) or just pass remote_pod=pod when you already have the V1Pod object from get_pods().

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Copilot finished work on behalf of jykae May 22, 2026 11:31
Copilot AI requested a review from jykae May 22, 2026 11:31
The new unit tests add several mock.MagicMock() instances (pods, jobs, TI, etc.) without spec/autospec, and some patch() usages also create non-spec'd mocks by default. Using autospec=True on patches and create_autospec(...)/MagicMock(spec=...) for key Kubernetes objects helps catch typos/attribute mismatches in these tests and aligns with Airflow’s test hardening guidance.

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 4 out of 4 changed files in this pull request and generated 4 comments.

Comment thread providers/cncf/kubernetes/tests/unit/cncf/kubernetes/operators/test_job.py Outdated
Copilot AI added 2 commits May 22, 2026 11:47
…nd test assertions

- triggers/job.py: Always include pod_names/pod_namespace in trigger event
  regardless of get_logs setting, so execute_complete() can reliably clean
  up monitoring pods even when get_logs=False
- operators/job.py: Log unexpected ApiException in on_kill() instead of
  suppressing all ApiExceptions; remove unused `suppress` import
- tests/test_job.py: Rewrite test_execute_respects_keep_pod and
  test_execute_deletes_pod_default to keep process_pod_deletion real and
  assert on pod_manager.delete_pod; stub hook.get_pod for remote_pod resolution
- tests/test_job.py: Add regression test for get_logs=False deferrable path
Copilot finished work on behalf of jykae May 22, 2026 11:50
@jykae jykae requested review from Copilot and removed request for Copilot May 22, 2026 11:50
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 5 out of 5 changed files in this pull request and generated 1 comment.

Copilot finished work on behalf of jykae May 22, 2026 11:59
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 5 out of 5 changed files in this pull request and generated 3 comments.

Comment thread providers/cncf/kubernetes/tests/unit/cncf/kubernetes/operators/test_job.py Outdated
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 5 out of 5 changed files in this pull request and generated 3 comments.

Comment thread providers/cncf/kubernetes/docs/operators.rst Outdated
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 5 out of 5 changed files in this pull request and generated 3 comments.

* ``delete_pod`` (default) — the pod is deleted after the task
finishes (success or failure).
* ``delete_succeeded_pod`` — the pod is deleted only when the task
succeeded.
Comment on lines +732 to +733
When the task is killed, ``on_kill`` deletes the Job (with foreground cascade)
and additionally attempts pod deletion directly for the discovered pods.
@@ -0,0 +1 @@
Fix pod cleanup gaps in ``KubernetesJobOperator``: ``execute()``, ``execute_complete()`` and ``on_kill()`` now consistently clean up pods discovered via ``get_pods()``, including deferrable resume paths where pod lookup can fail. The inherited ``on_finish_action`` parameter (``delete_pod`` / ``delete_succeeded_pod`` / ``keep_pod``) is honoured for these pods, matching ``KubernetesPodOperator`` behavior. Per-pod cleanup errors are logged but never mask a Job-level failure.
Copilot finished work on behalf of jykae May 22, 2026 12:47
Copilot AI requested a review from jykae May 22, 2026 12:47
@jykae jykae merged commit 7d3f581 into main May 22, 2026
@jykae jykae deleted the copilot/fix-kubernetesjoboperator-pod-leak branch May 22, 2026 12:48
jykae added a commit that referenced this pull request May 22, 2026
* fix(providers/cncf/kubernetes): clean up monitoring pods in KubernetesJobOperator

KubernetesJobOperator inherited from KubernetesPodOperator but overrode
execute() without calling post_complete_action(), so the monitoring /
log-streaming pods discovered via get_pods() were never deleted. These
pods have no ownerReferences to the V1Job, so ttl_seconds_after_finished
and the Foreground cascade in on_kill don't reap them either.

- execute() and execute_complete() now wrap their work in try/finally and
  call post_complete_action() for each pod in self.pods. on_finish_action
  (delete_pod / delete_succeeded_pod / keep_pod) is now honoured.
- on_kill() additionally calls pod_manager.delete_pod() for each
  monitoring pod (the Job's foreground cascade doesn't reach them).
- Per-pod cleanup errors are logged but never mask the in-flight
  exception, so Job-level failures keep propagating.
- execute_complete() resolves monitoring pods once and shares the lookup
  between the log-retrieval path and the cleanup path.
- Added unit tests, a bugfix newsfragment, and an operators.rst section
  documenting the cleanup contract.

* Address code review feedback: remove dead PodNotFoundException check, drop unused import, relax pod-deletion ordering in test, fix trailing comma

* Potential fix for pull request finding

In _cleanup_monitoring_pods, remote_pod is resolved via find_pod(), which is designed to locate a single matching pod by task-instance labels and can invoke duplicate-pod resolution logic (process_duplicate_label_pods). For KubernetesJobOperator with parallelism > 1, this lookup can return the wrong pod (or trigger duplicate-handling side effects), so post_complete_action() may receive a mismatched remote_pod. Consider using the already-discovered pod’s name/namespace to refresh state (e.g. via hook.get_pod) or just pass remote_pod=pod when you already have the V1Pod object from get_pods().

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* Use isinstance(exc, TaskDeferred) instead of brittle string comparison

* Potential fix for pull request finding

The new unit tests add several mock.MagicMock() instances (pods, jobs, TI, etc.) without spec/autospec, and some patch() usages also create non-spec'd mocks by default. Using autospec=True on patches and create_autospec(...)/MagicMock(spec=...) for key Kubernetes objects helps catch typos/attribute mismatches in these tests and aligns with Airflow’s test hardening guidance.

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* Address PR review comments: fix trigger pod_names, on_kill logging, and test assertions

- triggers/job.py: Always include pod_names/pod_namespace in trigger event
  regardless of get_logs setting, so execute_complete() can reliably clean
  up monitoring pods even when get_logs=False
- operators/job.py: Log unexpected ApiException in on_kill() instead of
  suppressing all ApiExceptions; remove unused `suppress` import
- tests/test_job.py: Rewrite test_execute_respects_keep_pod and
  test_execute_deletes_pod_default to keep process_pod_deletion real and
  assert on pod_manager.delete_pod; stub hook.get_pod for remote_pod resolution
- tests/test_job.py: Add regression test for get_logs=False deferrable path

* Fix orphaned test_on_kill_deletes_monitoring_pods method body after accidental deletion of method signature

* Make pod resolution best-effort in execute_complete

* Address remaining KubernetesJobOperator review comments

* Finalize review-comment fixes for KubernetesJobOperator

* Fix remaining KubernetesJobOperator review comments

* Update KubernetesJobOperator docs for action semantics

* Improve KubernetesJobOperator newsfragment readability

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Ville Jyrkkä <vjyrkka@gmail.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants