kaxil commented on code in PR #67715:
URL: https://github.com/apache/airflow/pull/67715#discussion_r3336889369
##########
providers/apache/spark/docs/operators.rst:
##########
@@ -214,3 +214,32 @@ See :doc:`connections/spark-submit` for how to configure
these fields.
.. note::
Crash recovery in cluster mode requires Airflow 3.3+ (``task_state``
support). On earlier
versions the operator falls back to the previous behavior of always
submitting fresh.
+
+Tracking driver status via Kubernetes API
+""""""""""""""""""""""""""""""""""""""""""
+
+When running in Kubernetes cluster mode, ``spark-submit`` blocks for the
duration of the job.
+The JVM runs processes which does nothing but polling of the pod phase and
holds heap space for
+the entire duration. This is not ideal for long-running jobs, especially when
the driver is idle
+for long periods (e.g. waiting for data or user input).
+
+Set ``track_driver_via_k8s_api=True`` to have the operator track the driver
pod status via the
+Python Kubernetes client rather than holding ``spark-submit`` open for the
full job duration:
+
+.. code-block:: python
+
+ from airflow.providers.apache.spark.operators.spark_submit import
SparkSubmitOperator
+
+ run_spark = SparkSubmitOperator(
+ task_id="run_spark",
+ application="local:///opt/spark/examples/jars/spark-examples.jar",
+ conn_id="spark_k8s",
+ deploy_mode="cluster",
+ track_driver_via_k8s_api=True,
+ )
+
+**Requirements**
+
+* The Spark connection ``master`` must be ``k8s://...`` and ``deploy_mode``
must be ``cluster``.
+* Do not set ``spark.kubernetes.submission.waitAppCompletion=true`` in your
``conf`` — this
+ conflicts with the flag and a ``ValueError`` will be raised at task start.
Review Comment:
Two caveats worth adding to this section. (1) Polling uses the worker's
default kube client (`get_kube_client()`), so the worker must be able to reach
the API server and delete pods in the driver's namespace; otherwise tracking
and cleanup fail. (2) The K8s-API tracking path bypasses `ResumableJobMixin`
(per the in-code TODO), so it doesn't reconnect on retry: if the worker dies or
the poll loop gives up, an Airflow retry submits a fresh driver instead of
reattaching to the existing one.
##########
providers/apache/spark/src/airflow/providers/apache/spark/hooks/spark_submit.py:
##########
@@ -268,6 +282,34 @@ def _resolve_should_track_driver_status(self) -> bool:
"""
return "spark://" in self._connection["master"] and
self._connection["deploy_mode"] == "cluster"
+ def _should_track_driver_via_k8s_api(self) -> bool:
+ return (
+ self._track_driver_via_k8s_api
+ and self._is_kubernetes
+ and self._connection["deploy_mode"] == "cluster"
+ )
+
+ def _validate_track_driver_via_k8s_api_config(self) -> None:
+ if not self._is_kubernetes:
+ raise ValueError(
+ "`track_driver_via_k8s_api=True` requires Spark master to be
Kubernetes (k8s://...)."
+ )
+ if self._connection["deploy_mode"] != "cluster":
+ raise ValueError(
+ "`track_driver_via_k8s_api=True` requires
`deploy_mode='cluster'`; "
+ f"got deploy_mode={self._connection['deploy_mode']!r}."
+ )
+ if not self._connection.get("namespace"):
+ raise ValueError(
+ "`track_driver_via_k8s_api=True` requires a namespace; "
+ "set it in the connection extra as `namespace` or via
`spark.kubernetes.namespace` in conf."
+ )
+ if self._conf.get(_K8S_WAIT_APP_COMPLETION_CONF, "").lower() == "true":
Review Comment:
`self._conf.get(_K8S_WAIT_APP_COMPLETION_CONF, "").lower()` raises
`AttributeError` if the value is passed as a non-string (e.g.
`conf={"spark.kubernetes.submission.waitAppCompletion": True}`). Spark conf is
conventionally string-valued, so it's an edge case, but `str(...).lower()`
would make the validation robust.
--
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]