You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Figure out how to retrieve Airflow configurations (from airflow.cfg) in the Task SDK without importing Airflow core.
Investigate different approaches for configuration architecture in separated server and SDK components, analyze trade-offs, and recommend the best approach.
Configuration Split Options to Investigate
Option 1: Complete Independence
Approach: Separate configuration files for server and SDK
Pros: Clean separation, no network dependencies
Cons: Configuration duplication, sync issues
Use case: When server and workers are in different environments
Option 2: API-Based Inheritance
Approach: SDK queries server API for configuration values
Pros: Centralized configuration management
Cons: Network dependency, potential latency
Use case: When workers need dynamic configuration updates
Option 3: Bootstrap Injection
Approach: Server injects essential config at task startup
Pros: No runtime API calls, centralized control
Cons: Static configuration, larger task payloads
Use case: When configuration is stable and performance is critical
Option 4: Hybrid Local-First + API Fallback
Approach: Local config first, API fallback for inherited values, caching
we have three
possible options to tell our users:.
either copy to workers only the configuration that is needed (but which
ones are needed and how to separate those config entries in the docs?)
or NO configuration should be present in the worker - and all
configuration that is needed should be passed by Task SDK to the worker
or we assess that task and dag file processors do not need any
configuration at all
I think if we assess that 3) is the case - there is no other option but to
remove conf. That would also be really nice as we would not have to have
"conf" reading code in TaskSDK at all.
But if we think that tasks and dag parsing will actually need some
configuration, then we can go either 1) or 2) route
I think option 2) is much better from less confusion, security and "single
source of truth" point of view. And if we go for 2) then namespace = conf.get("kubernetes", "NAMESPACE") will not work because configuration
will not be present there and in this case what would make more sense is to
leave "conf" as part of the context but only pass the "needed"
configuration there.
If we go for option 1) then likely yes we could remove it from context.
Alright, nice discussions above. I would be in favour of Option 1: Complete Independence as I think it is the most practical and architecturally sound approach with Airflow3 architecture. Let me explain the fundamental problems that eliminate Options 2, 3, and 4 from consideration:
Option 2: API-Based Inheritance
It creates network dependencies between the workers and the API server and now makes the workers running task sdk dependent on API server even for the most basic dag authoring experience, I do not know how we would be able to deal with operator and dag defaults here, not to mention it might turn into really huge payloads across the networks making a mark on performance of Airflow by having too many API calls and also by making "context" as a dumping groung.
Option 3: Bootstrap Injection
Could potentially lead into slower bootstrapping for configs that need to be calculated and it still requires API calls and doesn't solve the DAG processor/triggerer problem. Another issue I see is static nature of injected configuration means no dynamic updates are possible, leading to inconsistency when configuration changes on the server side while tasks are running (could be an issue for things like execution url changing)
Option 4: Hybrid Local-First + API Fallback
This is a decent option and my proposal would be more like a hybrid of option 4 and 1, but 4 in itself could be overly complex for very little benefit?
I propose that we move the AirflowConfigParser (not configs) to a shared module, while keeping the actual configuration files and values separate and independent for each component.
Each component now gets exactly what it needs - the shared parsing logic / abstraction to read and interpret configuration files, but with complete autonomy over what configuration values they actually contain.
Performed a small analysis on the pattern of conf imports used by the providers, there are 400+ usages which are mostly either provider configs, or operator related (task sdk), the only ones (non tests) using core are:
Activity
kaxil commentedon Dec 10, 2024
@potiuk 's options here: https://lists.apache.org/thread/8jtgr1m072lgsy4tl3km9ptb216vqjds
potiuk commentedon Dec 10, 2024
Thanks @kaxil - yeah, that's the right place to discuss it :)
AIP-72: Add some basic Task Context keys
AIP-72: Add some basic Task Context keys
7 remaining items
amoghrajesh commentedon Aug 25, 2025
@potiuk @kaxil
Alright, nice discussions above. I would be in favour of Option 1: Complete Independence as I think it is the most practical and architecturally sound approach with Airflow3 architecture. Let me explain the fundamental problems that eliminate Options 2, 3, and 4 from consideration:
Option 2: API-Based Inheritance
It creates network dependencies between the workers and the API server and now makes the workers running task sdk dependent on API server even for the most basic dag authoring experience, I do not know how we would be able to deal with operator and dag defaults here, not to mention it might turn into really huge payloads across the networks making a mark on performance of Airflow by having too many API calls and also by making "context" as a dumping groung.
Option 3: Bootstrap Injection
Could potentially lead into slower bootstrapping for configs that need to be calculated and it still requires API calls and doesn't solve the DAG processor/triggerer problem. Another issue I see is static nature of injected configuration means no dynamic updates are possible, leading to inconsistency when configuration changes on the server side while tasks are running (could be an issue for things like execution url changing)
Option 4: Hybrid Local-First + API Fallback
This is a decent option and my proposal would be more like a hybrid of option 4 and 1, but 4 in itself could be overly complex for very little benefit?
I propose that we move the
AirflowConfigParser(not configs) to a shared module, while keeping the actual configuration files and values separate and independent for each component.Each component now gets exactly what it needs - the shared parsing logic / abstraction to read and interpret configuration files, but with complete autonomy over what configuration values they actually contain.
amoghrajesh commentedon Aug 25, 2025
Performed a small analysis on the pattern of conf imports used by the providers, there are 400+ usages which are mostly either provider configs, or operator related (task sdk), the only ones (non tests) using core are:
core.securityproviders/apache/hdfs/src/airflow/providers/apache/hdfs/hooks/webhdfs.py_kerberos_security_mode = conf.get("core", "security") == "kerberos"core.securityproviders/apache/hive/src/airflow/providers/apache/hive/hooks/hive.pyif conf.get("core", "security") == "kerberos":(4 occurrences)core.execution_api_server_urlproviders/celery/src/airflow/providers/celery/executors/celery_executor_utils.pyserver=conf.get("core", "execution_api_server_url", fallback=default_execution_api_server)core.execution_api_server_urlproviders/edge3/src/airflow/providers/edge3/cli/worker.pyexecution_api_server_url = conf.get("core", "execution_api_server_url", fallback="")core.internal_api_clock_graceproviders/edge3/src/airflow/providers/edge3/worker_api/auth.pyclock_grace = conf.getint("core", "internal_api_clock_grace", fallback=30)core.internal_api_secret_keyproviders/edge3/src/airflow/providers/edge3/worker_api/auth.pysecret_key=conf.get("core", "internal_api_secret_key")core.PARALLELISMproviders/edge3/src/airflow/providers/edge3/executors/edge_executor.pyPARALLELISM: int = conf.getint("core", "PARALLELISM")core.dbapihook_resolve_target_fieldsproviders/common/sql/src/airflow/providers/common/sql/hooks/sql.py_resolve_target_fields = conf.getboolean("core", "dbapihook_resolve_target_fields", fallback=False)core.enable_xcom_picklingproviders/microsoft/azure/src/airflow/providers/microsoft/azure/operators/adx.pyif conf.getboolean("core", "enable_xcom_pickling", fallback=False):core.enable_xcom_picklingproviders/microsoft/winrm/src/airflow/providers/microsoft/winrm/operators/winrm.pyenable_pickling = conf.getboolean("core", "enable_xcom_pickling", fallback=False)core.enable_xcom_picklingproviders/ssh/src/airflow/providers/ssh/operators/ssh.pyenable_pickling = conf.getboolean("core", "enable_xcom_pickling", fallback=False)core.default_timezoneproviders/fab/src/airflow/providers/fab/www/extensions/init_jinja_globals.pyserver_timezone = conf.get("core", "default_timezone")Impact for Worker Configuration:
All these core settings must be included in worker configuration files since providers running on workers depend on them for proper functionality.
amoghrajesh commentedon Nov 25, 2025
Update on this one:
conffrom core etc can come after 3.1.2.task-sdkdependency fromairflow-core#62061amoghrajesh commentedon Mar 25, 2026
This issue can be worked on 3.3+ when we try to decouple providers from airflow-core. For now its fine.
amoghrajesh commentedon Jun 15, 2026
Wasn't committed for Airflow 3.3, moving to Airflow 3.4 as best effort work.