Repository navigation
Emit parse-time DAG warnings for partial dynamic factory failures #75673
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
b679d3d
71302a7
6687e42
bc6ada4
012f7c8
5fa8c1c
7553e8f
b32732c
8ea56de
bce386b
09abe70
3ccca6c
073439c
dc035ef
2ace141
80871c0
073e034
606930f
6eb6cd0
efe9a9d
8e6b52b
c1fd6ea
6e51ebe
c1f1c92
1edbb75
93aabca
aaa3d56
4f064e4
cfe7b05
575d4b2
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -52,7 +52,11 @@ | |||||||||||||||||||||||
| from airflow.models.dag import DagModel, DagOwnerAttributes, DagTag | ||||||||||||||||||||||||
| from airflow.models.dagbundle import DagBundleModel | ||||||||||||||||||||||||
| from airflow.models.dagrun import DagRun | ||||||||||||||||||||||||
| from airflow.models.dagwarning import DagWarning, DagWarningType | ||||||||||||||||||||||||
| from airflow.models.dagwarning import ( | ||||||||||||||||||||||||
| PARSE_FAILURE_WARNING_TYPE, | ||||||||||||||||||||||||
| DagWarning, | ||||||||||||||||||||||||
| DagWarningType, | ||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||
| from airflow.models.errors import ParseImportError | ||||||||||||||||||||||||
| from airflow.models.serialized_dag import SerializedDagModel | ||||||||||||||||||||||||
| from airflow.models.trigger import Trigger | ||||||||||||||||||||||||
|
|
@@ -383,6 +387,60 @@ def _update_dag_warnings( | |||||||||||||||||||||||
| session.merge(warning_to_add) | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| def build_dag_parse_failure_warnings( | ||||||||||||||||||||||||
| bundle_name: str, warnings_by_rel_path: dict[str, list] | ||||||||||||||||||||||||
| ) -> list[DagWarning]: | ||||||||||||||||||||||||
| return [ | ||||||||||||||||||||||||
| DagWarning( | ||||||||||||||||||||||||
| dag_id=record.dag_id, | ||||||||||||||||||||||||
| warning_type=record.warning_type, | ||||||||||||||||||||||||
| message=record.message, | ||||||||||||||||||||||||
| bundle_name=bundle_name, | ||||||||||||||||||||||||
| filename=rel_path, | ||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||
| for rel_path, records in warnings_by_rel_path.items() | ||||||||||||||||||||||||
| for record in records | ||||||||||||||||||||||||
| ] | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| def _update_file_scoped_parse_failure_warnings( | ||||||||||||||||||||||||
| files_parsed: set[tuple[str, str]], | ||||||||||||||||||||||||
| parse_failure_warnings: Iterable[DagWarning], | ||||||||||||||||||||||||
| session: Session, | ||||||||||||||||||||||||
| ) -> None: | ||||||||||||||||||||||||
|
Comment on lines
+406
to
+410
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit:
Suggested change
|
||||||||||||||||||||||||
| if files_parsed: | ||||||||||||||||||||||||
|
ydsakshi marked this conversation as resolved.
Resolved
|
||||||||||||||||||||||||
| session.execute( | ||||||||||||||||||||||||
| delete(DagWarning).where( | ||||||||||||||||||||||||
| tuple_(DagWarning.bundle_name, DagWarning.filename).in_(files_parsed), | ||||||||||||||||||||||||
| DagWarning.warning_type == PARSE_FAILURE_WARNING_TYPE, | ||||||||||||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||
| for warning in parse_failure_warnings: | ||||||||||||||||||||||||
| session.merge(warning) | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| def clear_orphaned_file_scoped_parse_failure_warnings( | ||||||||||||||||||||||||
| bundle_name: str, | ||||||||||||||||||||||||
| observed_filelocs: set[str], | ||||||||||||||||||||||||
| session: Session, | ||||||||||||||||||||||||
| ) -> None: | ||||||||||||||||||||||||
| """Remove parse-failure warnings for files that no longer exist in the bundle.""" | ||||||||||||||||||||||||
| try: | ||||||||||||||||||||||||
| warnings = session.scalars( | ||||||||||||||||||||||||
| select(DagWarning) | ||||||||||||||||||||||||
| .where( | ||||||||||||||||||||||||
| DagWarning.bundle_name == bundle_name, | ||||||||||||||||||||||||
| DagWarning.warning_type == PARSE_FAILURE_WARNING_TYPE, | ||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||
| .options(load_only(DagWarning.filename)) | ||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||
| for warning in warnings: | ||||||||||||||||||||||||
| if warning.filename not in observed_filelocs: | ||||||||||||||||||||||||
| session.delete(warning) | ||||||||||||||||||||||||
| except Exception: | ||||||||||||||||||||||||
| log.exception("Error removing old parse-failure DAG warnings") | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| def _update_import_errors( | ||||||||||||||||||||||||
| files_parsed: set[tuple[str, str]], | ||||||||||||||||||||||||
| import_errors: dict[tuple[str, str], str], | ||||||||||||||||||||||||
|
|
@@ -608,6 +666,7 @@ def update_dag_parsing_results_in_db( | |||||||||||||||||||||||
| warnings: set[DagWarning], | ||||||||||||||||||||||||
| session: Session, | ||||||||||||||||||||||||
| *, | ||||||||||||||||||||||||
| parse_failure_warnings: Iterable[DagWarning] | None = None, | ||||||||||||||||||||||||
| version_data: dict | None = None, | ||||||||||||||||||||||||
| warning_types: tuple[DagWarningType, ...] = ( | ||||||||||||||||||||||||
| DagWarningType.DUPLICATE_DAG_ID, | ||||||||||||||||||||||||
|
|
@@ -715,6 +774,15 @@ def update_dag_parsing_results_in_db( | |||||||||||||||||||||||
| except Exception: | ||||||||||||||||||||||||
| log.exception("Error logging DAG warnings.") | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| try: | ||||||||||||||||||||||||
| _update_file_scoped_parse_failure_warnings( | ||||||||||||||||||||||||
| files_parsed if files_parsed is not None else set(), | ||||||||||||||||||||||||
| parse_failure_warnings or (), | ||||||||||||||||||||||||
| session, | ||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||
| except Exception: | ||||||||||||||||||||||||
| log.exception("Error logging Dag parse failure warnings.") | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| session.flush() | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Anyone who can read one Dag in the file sees the stacktrace. For import errors from the same file, the API hides
the stacktrace unless the user can read all Dags in it. If no Dag in the file loaded, nobody can see the warning.