@@ -149,7 +149,8 @@ def _get_connection(conn_id: str) -> Connection:
149149 except SecretCache .NotPresentException :
150150 pass # continue to backends
151151
152- # iterate over configured backends if not in cache (or expired)
152+ # Iterate over configured backends (which may include SupervisorCommsSecretsBackend
153+ # in worker contexts or MetastoreBackend in API server contexts)
153154 backends = ensure_secrets_backend_loaded ()
154155 for secrets_backend in backends :
155156 try :
@@ -165,26 +166,10 @@ def _get_connection(conn_id: str) -> Connection:
165166 type (secrets_backend ).__name__ ,
166167 )
167168
168- if backends :
169- log .debug (
170- "Connection not found in any of the configured Secrets Backends. Trying to retrieve from API server" ,
171- conn_id = conn_id ,
172- )
173-
174- # TODO: This should probably be moved to a separate module like `airflow.sdk.execution_time.comms`
175- # or `airflow.sdk.execution_time.connection`
176- # A reason to not move it to `airflow.sdk.execution_time.comms` is that it
177- # will make that module depend on Task SDK, which is not ideal because we intend to
178- # keep Task SDK as a separate package than execution time mods.
179- # Also applies to _async_get_connection.
180- from airflow .sdk .execution_time .comms import GetConnection
181- from airflow .sdk .execution_time .task_runner import SUPERVISOR_COMMS
182-
183- msg = SUPERVISOR_COMMS .send (GetConnection (conn_id = conn_id ))
169+ # If no backend found the connection, raise an error
170+ from airflow .exceptions import AirflowNotFoundException
184171
185- conn = _process_connection_result_conn (msg )
186- SecretCache .save_connection_uri (conn_id , conn .get_uri ())
187- return conn
172+ raise AirflowNotFoundException (f"The conn_id `{ conn_id } ` isn't defined" )
188173
189174
190175async def _async_get_connection (conn_id : str ) -> Connection :
@@ -201,34 +186,36 @@ async def _async_get_connection(conn_id: str) -> Connection:
201186 _mask_connection_secrets (conn )
202187 return conn
203188 except SecretCache .NotPresentException :
204- pass # continue to API
189+ pass # continue to backends
205190
206- from airflow .sdk .execution_time .comms import GetConnection
207191 from airflow .sdk .execution_time .supervisor import ensure_secrets_backend_loaded
208- from airflow .sdk .execution_time .task_runner import SUPERVISOR_COMMS
209192
210- # Try secrets backends first using async wrapper
193+ # Try secrets backends
211194 backends = ensure_secrets_backend_loaded ()
212195 for secrets_backend in backends :
213196 try :
214- conn = await sync_to_async (secrets_backend .get_connection )(conn_id ) # type: ignore[assignment]
197+ # Use async method if available, otherwise wrap sync method
198+ if hasattr (secrets_backend , "aget_connection" ):
199+ conn = await secrets_backend .aget_connection (conn_id ) # type: ignore[assignment]
200+ else :
201+ conn = await sync_to_async (secrets_backend .get_connection )(conn_id ) # type: ignore[assignment]
202+
215203 if conn :
216- # TODO: this should probably be in get conn
217- if conn .password :
218- mask_secret (conn .password )
219- if conn .extra :
220- mask_secret (conn .extra )
204+ SecretCache .save_connection_uri (conn_id , conn .get_uri ())
205+ _mask_connection_secrets (conn )
221206 return conn
222207 except Exception :
223208 # If one backend fails, try the next one
224- continue
209+ log .exception (
210+ "Unable to retrieve connection from secrets backend (%s). "
211+ "Checking subsequent secrets backend." ,
212+ type (secrets_backend ).__name__ ,
213+ )
214+
215+ # If no backend found the connection, raise an error
216+ from airflow .exceptions import AirflowNotFoundException
225217
226- # If no secrets backend has the connection, fall back to API server
227- msg = await SUPERVISOR_COMMS .asend (GetConnection (conn_id = conn_id ))
228- conn = _process_connection_result_conn (msg )
229- SecretCache .save_connection_uri (conn_id , conn .get_uri ())
230- _mask_connection_secrets (conn )
231- return conn
218+ raise AirflowNotFoundException (f"The conn_id `{ conn_id } ` isn't defined" )
232219
233220
234221def _get_variable (key : str , deserialize_json : bool ) -> Any :
@@ -250,7 +237,8 @@ def _get_variable(key: str, deserialize_json: bool) -> Any:
250237 pass # Continue to check backends
251238
252239 backends = ensure_secrets_backend_loaded ()
253- # iterate over backends if not in cache (or expired)
240+
241+ # Iterate over backends if not in cache (or expired)
254242 for secrets_backend in backends :
255243 try :
256244 var_val = secrets_backend .get_variable (key = key )
@@ -270,31 +258,13 @@ def _get_variable(key: str, deserialize_json: bool) -> Any:
270258 type (secrets_backend ).__name__ ,
271259 )
272260
273- if backends :
274- log .debug (
275- "Variable not found in any of the configured Secrets Backends. Trying to retrieve from API server" ,
276- key = key ,
277- )
278-
279- # TODO: This should probably be moved to a separate module like `airflow.sdk.execution_time.comms`
280- # or `airflow.sdk.execution_time.variable`
281- # A reason to not move it to `airflow.sdk.execution_time.comms` is that it
282- # will make that module depend on Task SDK, which is not ideal because we intend to
283- # keep Task SDK as a separate package than execution time mods.
284- from airflow .sdk .execution_time .comms import ErrorResponse , GetVariable
285- from airflow .sdk .execution_time .task_runner import SUPERVISOR_COMMS
286-
287- msg = SUPERVISOR_COMMS .send (GetVariable (key = key ))
288-
289- if isinstance (msg , ErrorResponse ):
290- raise AirflowRuntimeError (msg )
261+ # If no backend found the variable, raise a not found error (mirrors _get_connection)
262+ from airflow .sdk .exceptions import AirflowRuntimeError , ErrorType
263+ from airflow .sdk .execution_time .comms import ErrorResponse
291264
292- if TYPE_CHECKING :
293- assert isinstance (msg , VariableResult )
294- variable = _convert_variable_result_to_variable (msg , deserialize_json )
295- # Save raw value to ensure cache consistency regardless of deserialize_json parameter
296- SecretCache .save_variable (key , msg .value )
297- return variable .value
265+ raise AirflowRuntimeError (
266+ ErrorResponse (error = ErrorType .VARIABLE_NOT_FOUND , detail = {"message" : f"Variable { key } not found" })
267+ )
298268
299269
300270def _set_variable (key : str , value : Any , description : str | None = None , serialize_json : bool = False ) -> None :
@@ -307,18 +277,21 @@ def _set_variable(key: str, value: Any, description: str | None = None, serializ
307277
308278 from airflow .sdk .execution_time .cache import SecretCache
309279 from airflow .sdk .execution_time .comms import PutVariable
280+ from airflow .sdk .execution_time .secrets .execution_api import ExecutionAPISecretsBackend
310281 from airflow .sdk .execution_time .supervisor import ensure_secrets_backend_loaded
311282 from airflow .sdk .execution_time .task_runner import SUPERVISOR_COMMS
312283
313284 # check for write conflicts on the worker
314285 for secrets_backend in ensure_secrets_backend_loaded ():
286+ if isinstance (secrets_backend , ExecutionAPISecretsBackend ):
287+ continue
315288 try :
316289 var_val = secrets_backend .get_variable (key = key )
317290 if var_val is not None :
318291 _backend_name = type (secrets_backend ).__name__
319292 log .warning (
320293 "The variable %s is defined in the %s secrets backend, which takes "
321- "precedence over reading from the database . The value in the database will be "
294+ "precedence over reading from the API Server . The value from the API Server will be "
322295 "updated, but to read it you have to delete the conflicting variable "
323296 "from %s" ,
324297 key ,
@@ -379,12 +352,16 @@ def __eq__(self, other):
379352 return True
380353
381354 def get (self , conn_id : str , default_conn : Any = None ) -> Any :
355+ from airflow .exceptions import AirflowNotFoundException
356+
382357 try :
383358 return _get_connection (conn_id )
384359 except AirflowRuntimeError as e :
385360 if e .error .error == ErrorType .CONNECTION_NOT_FOUND :
386361 return default_conn
387362 raise
363+ except AirflowNotFoundException :
364+ return default_conn
388365
389366
390367class VariableAccessor :
0 commit comments