You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@flink.apache.org by "Aniruddh J (Jira)" <ji...@apache.org> on 2026/07/23 17:58:00 UTC
[jira] [Created] (FLINK-40226) Standalone session cluster JM recovery enters infinite MISSING loop and fails with HTTP 409 on TM Deployment when TaskManager pods still exist
Aniruddh J created FLINK-40226:
----------------------------------
Summary: Standalone session cluster JM recovery enters infinite MISSING loop and fails with HTTP 409 on TM Deployment when TaskManager pods still exist
Key: FLINK-40226
URL: https://issues.apache.org/jira/browse/FLINK-40226
Project: Flink
Issue Type: Bug
Components: Kubernetes Operator
Affects Versions: 1.14.0, 1.11.0
Environment: Operator version 1.11.0, 1.14.0 (the ones I have tested it on)
Flink version1.20.x (standalone mode)
Cluster typeStandalone Kubernetes session cluster ({{{}FlinkDeployment{}}} with no {{{}spec.job{}}})
Kubernetes reproduced on OpenShift and vanilla Kubernetes
HA Enabled
Reporter: Aniruddh J
When the *JobManager (JM) Deployment* of a standalone Kubernetes session cluster is deleted externally (e.g. by an admin) while the {*}TaskManager (TM) Deployment and its pods are still running or terminating{*}, the operator enters a state where it can never successfully recover the session cluster. Two distinct but related defects combine to produce this outcome:
# *Bug 1 — Infinite MISSING status loop on submit failure.* {{recoverSession()}} in {{SessionReconciler}} does not set the {{JobManagerDeploymentStatus}} to {{DEPLOYING}} before calling {{{}submitSessionCluster(){}}}. If the submit call throws, the controller's error-handling path resets the status back to {{{}MISSING{}}}, causing {{shouldRecoverDeployment()}} to fire on every subsequent reconcile cycle — producing an unbound retry loop with no back-off.
# *Bug 2 — HTTP 409 AlreadyExists on TM Deployment re-creation.* {{deployClusterInternal()}} in {{KubernetesStandaloneClusterDescriptor}} uses a bare Kubernetes {{CREATE}} (HTTP POST) for the TaskManager Deployment via {{{}Fabric8FlinkStandaloneKubeClient.createTaskManagerDeployment(){}}}. If the TM Deployment already exists — which is the normal state when only the JM was deleted — the API server returns {{{}HTTP 409 Conflict (AlreadyExists){}}}, causing every recovery attempt to fail. This failure feeds back into Bug 1.
Together, the operator logs a continuous stream of reconciliation errors and the session cluster remains permanently unrecoverable until manual operator intervention.
h2. Steps to Reproduce
# Deploy a standalone Kubernetes session cluster (HA mode enabled) using {{{}FlinkDeployment{}}}. Wait for {{{}jobManagerDeploymentStatus: READY{}}}.
# Manually delete only the *JM Deployment* from the namespace:
{{kubectl delete deployment <cluster-id> -n <namespace>}}
# Do _not_ delete the TM Deployment or its pods — allow them to continue running.
# Observe the operator logs. The operator detects {{MISSING}} and calls {{{}recoverSession(){}}}.
# {{deployClusterInternal()}} attempts to re-create the TM Deployment via a bare HTTP POST. Because the TM Deployment still exists, the API server returns {{{}HTTP 409 AlreadyExists{}}}.
# The 409 exception propagates through {{submitSessionCluster()}} → {{recoverSession()}} → controller error handler.
# The controller error handler resets the status to {{MISSING}} from the in-memory cache (which was never updated to {{{}DEPLOYING{}}}).
# On the next reconcile cycle (15 s default), {{shouldRecoverDeployment()}} evaluates to {{true}} again, and the loop repeats indefinitely.
h2. Expected Behaviour
# When a JM-recovery submit fails for any transient reason (network error, 409, throttling), the {{jobManagerDeploymentStatus}} should be advanced to {{DEPLOYING}} _before_ the submit attempt, so that the error path does not restore {{MISSING}} and re-trigger an immediate retry.
# A re-submit when only the JM Deployment is absent and the TM Deployment still exists should succeed without a 409. The desired TM spec is unchanged, so an idempotent create-or-replace is semantically correct.
# A failed recovery attempt should not proactively delete or disturb still-running TM pods as part of its error rollback.
--
This message was sent by Atlassian Jira
(v8.20.10#820010)