Fix in-process Execution API secrets routing in client contexts - #65587
Fix in-process Execution API secrets routing in client contexts#65587henry3260 wants to merge 1 commit into
Conversation
6758f3a to
c8ece7f
Compare
c8ece7f to
6dc8178
Compare
|
Could someone please take a look at this PR when they have a chance? Thanks! |
d68c027 to
73528bb
Compare
ca97e7f to
5fc80b5
Compare
jason810496
left a comment
There was a problem hiding this comment.
Nice! Thanks for the fix.
Additionally, could we add test for the scenario mentioned in the issue (#65482) to make sure the expected behavior?
Thanks.
b21962b to
0a6ed36
Compare
jason810496
left a comment
There was a problem hiding this comment.
Please correct me if my understanding is wrong.
Another direction: How about adding lifespan to ensure SUPERVISOR_COMMS will be initialized for in-process Execution API?
Additionally, it would be nice to add airflow-e2e test for airflow dag test command with common scenarios as follow-up.
I think lifespan is the wrong scope for this. It initializes app-scoped state once at startup, but the issue here is request-scoped |
There was a problem hiding this comment.
How about adding
lifespanto ensureSUPERVISOR_COMMSwill be initialized for in-process Execution API?I think lifespan is the wrong scope for this. It initializes app-scoped state once at startup, but the issue here is request-scoped we need to isolate an in-process Execution API request from the outer client context. Initializing
SUPERVISOR_COMMSin lifespan would make that client marker app-wide and could leak it into server-side request handling wdyt?
For dag.test() command, it will use InProcessTestSupervisor under the hook, which means all the request will be processed in process. I'm not sure will there be race condition for override_process_context (when the _PROCESS_CONTEXT_OVERRIDE.reset teardown).
IMO, it's no harm to set the lifespan for InProcessTestSupervisor only app (override the app instance in _api_client factory method)
I understand your concern! Since |
0a6ed36 to
7bf1b8e
Compare
7ba1d43 to
5f76bd2
Compare
|
Moving to 3.3.1 and planning only to include critical/high priority bug fixes to 3.3.0 found in 3.3.0b2. |
77e0502 to
d07c383
Compare
|
@kaxil Would you mind taking a look when you have a moment? Thanks! |
|
Added maintainer review label |
|
Have you been able to run the repro from #65482 against this branch? I applied it locally and the reported scenario still hangs, so I don't think this closes that issue. What I ran: the script from the issue, with On main the run hangs, and the log shows With this branch applied the warning is gone and the handler resolves through the metastore, so The child never gets a response, because def send_msg(self, msg, request_id, error=None, **dump_opts):
"""Override to use in-process comms."""
self.comms.messages.append(msg)
If I route responses for socket-delivered requests back onto the socket, the repro passes on plain main, without this branch. Applying this branch on top produces the same value, minus one round trip through the SDK client and the deprecation warning. In the in-process path the nested call is already covered by So as far as I can tell this is a robustness fix on that path rather than the fix for #65482. |
Under dag.test() the Execution API server and the task share one process, so the API's own route handlers can see SUPERVISOR_COMMS. They took that as proof they were client-side and issued a fresh Execution API request, calling back into themselves instead of reading the metastore. Operators that spawn their own child process — PythonVirtualenvOperator and ExternalPythonOperator — have that child reconnect to the supervisor over a socket. The in-process supervisor answered every request on an in-memory queue the child cannot read, so it stayed blocked on a response frame that was never written: no error, no timeout, no traceback.
d07c383 to
0a6a3ad
Compare
Thanks for the detailed diagnosis, @kaxil — you're right on all counts. I spent time reading through the code to confirm the root cause you pointed out, and I've reworked the PR around it. Summary of what changed in
PTAL when you have a moment, thanks! |
Why
Execution API requests can run inside in-process paths where
SUPERVISOR_COMMSis present, which may incorrectly classify server-side code as client-side Task SDK execution.When that
happens, Variable or Connectionreads can route back into Task SDK paths instead of staying server-side, creating a recursive chain and potential hangs.The previous context signal was primarily environment-based, which is not always safe for request-scoped behavior in threaded in-process execution.
Because of that,
VariableandConnectionoperations triggered while serving in-process Execution APIrequests could still be routed back through Task SDK APIs instead of using the server-side secrets/backend
path, leading to recursive self-calls and hanging lookups.
closes: #65482
Was generative AI tooling used to co-author this PR?
{pr_number}.significant.rst, in airflow-core/newsfragments. You can add this file in a follow-up commit after the PR is created so you know the PR number.Important
🛠️ Maintainer triage note for @henry3260 · by
@potiuk· 2026-06-17 18:53 UTCSome review feedback from
jason810496,jschefflis waiting on you:The ball is in your court — you've been assigned to this PR. Reply or push a fix in each thread, then mark them resolved.
Automated triage — may be imperfect; a maintainer takes the next look.