noamst-monday opened a new pull request, #70595:
URL: https://github.com/apache/airflow/pull/70595
## Problem
`KubernetesPodOperator` in synchronous (`deferrable=False`) mode polls pod
status every ~2 seconds inside `await_pod_completion`. When a pod transitions
to `Succeeded`, there is up to a 2-second window before KPO observes the
terminal phase. The `airflow kubernetes cleanup-pods` command currently deletes
Succeeded/Failed/Evicted pods **immediately** — there is no minimum-age guard
for terminal states.
If the cleanup job fires during that window, KPO's next `read_pod` call
returns 404 and the task is marked **FAILED**, even though the pod completed
successfully (exit code 0).
A `--min-pending-minutes` guard already exists for Pending pods (default 30
m, minimum 5 m). No equivalent exists for terminal states.
### Real-world reproduction
This was confirmed via Kubernetes API server audit logs on a production EKS
cluster running `apache-airflow-providers-cncf-kubernetes==10.19.0` on Airflow
3.2.2. The cleanup CronJob was set to run every 5 minutes.
Timeline of a representative failure:
```
13:15:12Z KPO polls pod → phase Running
13:15:14Z Container exits → exit code 0 (pod phase → Succeeded)
13:15:17Z cleanup-pods deletes pod → 3 s after completion
13:15:18Z KPO polls pod → 404 Not Found → task FAILED
```
The pod had succeeded; the task failure was a false positive. Multiple DAGs
exhibited the same pattern on the same day.
Airflow task log excerpt:
```
[INFO] Pod run-o1sxc2on has phase Running
[ERROR] Task failed with exception
ApiException: (404) Reason: Not Found
HTTP response body: {"message":"pods \"run-o1sxc2on\" not
found","reason":"NotFound","code":404}
```
Audit log at deletion time confirmed `phase: Succeeded`,
`containerStatuses[0].state.terminated.exitCode: 0`, `finishedAt: 13:15:14Z`.
**Reducing the CronJob frequency is a partial mitigation** (lowers
probability) but does not eliminate the race — the window is a function of the
poll interval, not the CronJob frequency.
### Related
PR #69269 fixed a similar 404 race in `is_istio_enabled` for the deferrable
`trigger_reentry` path (merged into 10.20.0). This PR addresses the
complementary gap: preventing the race at source by not deleting
recently-completed pods.
## Solution
Add `--min-completed-minutes` (default `0`, preserving existing behaviour)
to the `cleanup-pods` command. When set to any positive value,
Succeeded/Failed/Evicted pods are skipped unless their completion time exceeds
the threshold.
Completion time is derived from
`max(containerStatuses[*].state.terminated.finishedAt)` — the latest container
finish time across all containers — which is the most accurate signal for "when
the pod entered a terminal state". Falls back to `metadata.creationTimestamp`
for pods evicted before any container started.
Setting `--min-completed-minutes=5` gives KPO a 5-minute observation window
— 150× wider than the 2 s poll interval — closing the race completely in
practice.
## Changes
| File | Change |
|---|---|
| `cli/definition.py` | Add `ARG_MIN_COMPLETED_MINUTES` (default `0`,
`allow_zero=True`); wire into cleanup-pods args |
| `cli/kubernetes_command.py` | Add `_get_pod_completion_time()` helper;
gate terminal-pod deletion by age |
| `tests/.../test_kubernetes_command.py` | 4 new unit tests (too-young
Succeeded, old-enough Succeeded, default=0 backward compat, too-young
Failed/Never) |
| `docs/changelog.rst` | Entry under 10.21.0 |
CLI reference docs (`cli-ref.rst`) use `.. argparse::` and pick up the new
flag automatically.
## Testing
```bash
pytest
providers/cncf/kubernetes/tests/unit/cncf/kubernetes/cli/test_kubernetes_command.py::TestCleanUpPodsCommand
-v
```
All existing tests continue to pass (default=0 preserves current behaviour).
Four new tests cover the new flag.
## Usage
In the cleanup CronJob, add the flag:
```bash
airflow kubernetes cleanup-pods --namespace airflow --min-completed-minutes 5
```
Or in the Airflow Helm chart values:
```yaml
cleanup:
args: ["bash", "-c", "exec airflow kubernetes cleanup-pods --namespace {{
.Release.Namespace }} --min-completed-minutes 5"]
```
---
##### Was generative AI tooling used to co-author this PR?
- [X] Yes (Claude Sonnet 4.6)
Generated-by: Claude Sonnet 4.6 following [the
guidelines](https://github.com/apache/airflow/blob/main/contributing-docs/05_pull_requests.rst#gen-ai-assisted-contributions)
---
* Read the **[Pull Request
Guidelines](https://github.com/apache/airflow/blob/main/contributing-docs/05_pull_requests.rst#pull-request-guidelines)**
for more information.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]