[AIP-85] Add configuration support for custom DAG importers - #72442
[AIP-85] Add configuration support for custom DAG importers#72442dilnazanlid wants to merge 3 commits into
Conversation
16d9180 to
936de37
Compare
SameerMesiah97
left a comment
There was a problem hiding this comment.
Not an expert here but this looks fairly clean from my perspective but we need to wait for CI to be triggered as there is a high risk of breaking changes here. I have left some comments.
| for x in list_py_file_paths(bundle.path, safe_mode=self.dag_discovery_safe_mode) | ||
| ] | ||
| importer_registry = bundle.importer_registry | ||
| dag_files = importer_registry.list_dag_files(bundle.path, safe_mode=self.dag_discovery_safe_mode) |
There was a problem hiding this comment.
Correct me if I am wrong (I am not as familiar with the DAG processor), but it looks like explicitly configured extensions are only used for registry lookup, not file discovery. For example, configring PythonDegImporter for "custom" makes get_importer("dag.custom") succeed, but list_dag_files() delegates to PythonDagImporter.list_dag_files(), which only discovers Python files and ZIP archives. Would custom files therefore never reach parsing?
There was a problem hiding this comment.
Good catch!
Currently, explicit extensions in the configuration only register entries in DagImporterRegistry._importers (affecting get_importer() and can_handle()), but registry.list_dag_files() delegates directly to importer.list_dag_files().
Because AbstractDagImporter.list_dag_files() inspects self.supported_extensions() (which is a @classmethod returning class-level defaults), files with custom configured extensions like dag.custom are filtered out during directory discovery. Consequently, they are never enqueued by DagFileProcessorManager and never reach parsing during normal bundle execution.
Proposed fix:
DagImporterRegistry.list_dag_files()performs a single walk of the bundle directory.- Each file is checked against
registry.get_importer(file_path). If matched, content validation / safe mode is delegated toimporter.might_contain_dag(file_path, safe_mode). - We associate the configured extensions(global or bundle-level) with the importer instance (
importer.set_configured_extensions()) so thatimporter.can_handle()andimporter.supported_extensionsstay consistent with the registry.
This will fix file discovery for custom extensions, avoids running N redundant filesystem walks across multiple importers, and strictly enforces extension override precedence.
WDYT? I will implement it for this change into the dag_processing/importers base classes. However, the importers are moved into the SDK in #72369 along with DagDefinition abstraction replacing the filesystem path approach, so it will also be reflected there.
There was a problem hiding this comment.
Added the changes specified above, seems like it solves the problem and tried to make them follow the best practice, PTAL
There was a problem hiding this comment.
Could you trigger CI?
…d extensions reach parsing instead of being ignored by hardcoded defaults.
Project Board: AIP-85 Dag Importer (Project #672)
This pull request is one of the incremental parts of the AIP-85: DAG Importer implementation.
Description
This pull request is part of the implementation of AIP-85: DAG Importer. It introduces configuration-driven registration and resolution for custom Dag importers at both the global and Dag bundle levels.
Prior to this change, Dag file discovery and parsing were tied to built-in Python file discovery (
list_py_file_paths), and theDagImporterRegistryoperated strictly as a singleton with hardcoded defaults. This PR introduces a configurable, tiered Dag importer resolution mechanism:Shared Module Loading (
airflow_shared.module_loading.dag_importers):load_dag_importers()utility to dynamically instantiate importer classes viaclasspathandkwargs.extensionsconfiguration per importer, falling back to the importer'ssupported_extensionsattribute or method.AirflowConfigExceptionon malformed inputs.3-Tier Importer Registry Precedence in Dag Bundles (
DagBundlesManager):_ExternalBundleConfig,_InternalBundleConfig) to support an optionalimporterslist.DagImporterRegistry:bundle.importers): Importers explicitly declared for that specific bundle (highest priority).[dag_processor] dag_importer_configs): System-wide custom importers configured via Airflow config.PythonDagImporterhandling.pyand.zipfiles (baseline fallback).bundle.importer_registryproperty toBaseDagBundleand cached per-bundle registries inDagBundlesManager.Instantiable
DagImporterRegistry:DagImporterRegistryfrom a rigid process-wide singleton into an instantiable class, allowing isolated registries per Dag bundle while preservingget_importer_registry()for global access.register()to allow custom extension lists and log informative warnings when an extension mapping is overridden by a higher-priority importer.Integration with File Discovery and
DagBag:DagFileProcessorManager._find_files_in_bundle()to discover Dag files dynamically usingbundle.importer_registry.list_dag_files().DagBagto accept and utilize bundle-scopedimporter_registryinstances during Dag parsing and collection.Tests:
airflow_shared.module_loading.test_dag_bundle_manager.pyverifying the 3-tier precedence rules, extension overrides, nested composite importers, and error handling.test_registry.pyandtest_manager.pyto cover independent registry instances and bundle discovery.Was generative AI tooling used to co-author this PR?
Generated-by: Google Gemini following the guidelines