vatsrahul1001 opened a new pull request, #68819:
URL: https://github.com/apache/airflow/pull/68819

   ### Problem
   
   When the scheduler runs **in-cluster**, the kubernetes Python client 
attaches an in-cluster `Configuration` to every `V1Pod`, and that 
`Configuration.refresh_api_key_hook` is a **local closure** 
(`InClusterConfigLoader._set_config.<locals>._refresh_api_key`). `pickle` 
cannot serialize a local closure.
   
   `KubernetesExecutor` puts each task's `KubernetesJob` (which embeds the 
task's `pod_override` `V1Pod`) onto a `multiprocessing.Manager` queue, whose 
`.put()` pickles synchronously in the scheduler. So any in-cluster deployment 
where a task sets a `V1Pod` `pod_override` crashes the scheduler in a loop:
   
   ```
   _pickle.PicklingError: Can't pickle local object
     <function InClusterConfigLoader._set_config.<locals>._refresh_api_key at 
...>
   when serializing kubernetes.client.configuration.Configuration ...
   when serializing dict item 'pod_override'
   when serializing ... ExecuteTask ...
     File ".../executors/kubernetes_executor.py", line 230, in execute_async
       self.task_queue.put(KubernetesJob(key, command, kube_executor_config, 
pod_template_file))
   ```
   
   This is **independent of the Airflow version** — it is gated on having a 
`V1Pod` `pod_override` and an in-cluster scheduler. It surfaces with kubernetes 
client **36.x** (whose `Configuration` carries the unpicklable hook), and 
pinning the client is not a viable fix for everyone (35.x has its own 
[`no_proxy` bug 
#2520](https://github.com/kubernetes-client/python/issues/2520), so deployments 
that need 36.x for that fix cannot downgrade).
   
   ### Fix
   
   Serialize the `pod_override` to a plain dict (dropping the `Configuration`) 
**before** it is queued, using the existing `PodGenerator.serialize_pod`, and 
rebuild the `V1Pod` worker-side in `run_next` via 
`PodGenerator.deserialize_model_dict`. The worker already reconstructs its own 
kube client, so nothing is lost. The worker uses `kube_executor_config` for the 
pod override; the same `V1Pod` is also referenced by the workload's 
`executor_config`, so that copy is sanitized too (it is otherwise pickled as 
part of the workload).
   
   This keeps `pod_override` working regardless of the kubernetes client 
version, rather than depending on a client version whose `Configuration` 
happens to be picklable. The worker side already sanitizes pods with 
`sanitize_for_serialization` (kubernetes_executor_utils.py:492) — this closes 
the same gap on the scheduler→queue boundary.
   
   ### Tests
   
   - New regression test `test_execute_async_queues_picklable_pod_override`: 
builds a `pod_override` whose `Configuration` carries an unpicklable 
local-closure hook, asserts the raw pod is unpicklable (reproduces the crash), 
then asserts the queued `KubernetesJob` pickles cleanly and the serialized dict 
round-trips back to an equivalent `V1Pod`.
   - Updated `test_pod_template_file_override_in_executor_config` to reflect 
the queued `kube_executor_config` now being a dict; its existing `run_next` 
round-trip assertion (the reconstructed pod) is unchanged and still passes.
   - Full `test_kubernetes_executor.py` suite passes (111 passed, 1 skipped 
AF<3.2-only).
   
   ---
   
   ##### Was generative AI tooling used to co-author this PR?
   
   - [X] Yes — Claude Code (Opus 4.8)
   
   Generated-by: Claude Code (Opus 4.8) following [the 
guidelines](https://github.com/apache/airflow/blob/main/contributing-docs/05_pull_requests.rst#gen-ai-assisted-contributions)


-- 
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]

Reply via email to