Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 17.7k
Add run_on_latest_version support for backfill and clear operations#52177
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
Uh oh!
There was an error while loading. Please reload this page.
Changes from all commits
1109cadfafb74439ebf82d56138891d57c28655ca9e13778bac6d4cd120dbc68ce6088db415ce73eec265d7dca3a6a1496File filter
Filter by extension
Conversations
Uh oh!
There was an error while loading. Please reload this page.
Jump to
Uh oh!
There was an error while loading. Please reload this page.
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -84,8 +84,10 @@ def create_app(apps: str = "all") -> FastAPI: | ||
| dag_bag = create_dag_bag() | ||
| if "execution" in apps_list or "all" in apps_list: | ||
| from airflow.jobs.scheduler_job_runner import SchedulerDagBag | ||
| task_exec_api_app = create_task_execution_api_app() | ||
| task_exec_api_app.state.dag_bag = dag_bag | ||
| task_exec_api_app.state.dag_bag = SchedulerDagBag() | ||
| init_error_handlers(task_exec_api_app) | ||
jason810496 marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| app.mount("/execution", task_exec_api_app) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -8396,6 +8396,12 @@ components: | ||
| type: boolean | ||
| title: Include Past | ||
| default: false | ||
| run_on_latest_version: | ||
| type: boolean | ||
| title: Run On Latest Version | ||
ephraimbuddy marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| description: (Experimental) Run on the latest bundle version of the DAG | ||
| after clearing the task instances. | ||
| default: false | ||
| additionalProperties: false | ||
| type: object | ||
| title: ClearTaskInstancesBody | ||
| @@ -9049,6 +9055,12 @@ components: | ||
| type: boolean | ||
| title: Only Failed | ||
| default: false | ||
| run_on_latest_version: | ||
| type: boolean | ||
| title: Run On Latest Version | ||
| description: (Experimental) Run on the latest bundle version of the DAG | ||
| after clearing the DAG Run. | ||
| default: false | ||
| additionalProperties: false | ||
| type: object | ||
| title: DAGRunClearBody | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -29,7 +29,6 @@ | ||
| from airflow.api_fastapi.execution_api.datamodels.dagrun import DagRunStateResponse, TriggerDAGRunPayload | ||
| from airflow.exceptions import DagRunAlreadyExists | ||
| from airflow.models.dag import DagModel | ||
| from airflow.models.dagbag import DagBag | ||
| from airflow.models.dagrun import DagRun | ||
| from airflow.utils.types import DagRunTriggeredByType | ||
| @@ -122,9 +121,20 @@ def clear_dag_run( | ||
| "message": f"DAG with dag_id: '{dag_id}' has import errors and cannot be triggered", | ||
| }, | ||
| ) | ||
| from airflow.jobs.scheduler_job_runner import SchedulerDagBag | ||
| dag_run = session.scalar(select(DagRun).where(DagRun.dag_id == dag_id, DagRun.run_id == run_id)) | ||
| dag_bag = SchedulerDagBag() | ||
jason810496 marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. jedcunningham marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| dag = dag_bag.get_dag(dag_run=dag_run, session=session) | ||
| if not dag: | ||
| raise HTTPException( | ||
| status.HTTP_404_NOT_FOUND, | ||
| detail={ | ||
| "reason": "Not Found", | ||
| "message": f"DAG with dag_id: '{dag_id}' was not found in the DagBag", | ||
| }, | ||
| ) | ||
| dag_bag = DagBag(dag_folder=dm.fileloc, read_dags_from_db=True) | ||
| dag = dag_bag.get_dag(dag_id) | ||
| dag.clear(run_id=run_id) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -29,15 +29,15 @@ | ||
| import attrs | ||
| import structlog | ||
| from cadwyn import VersionedAPIRouter | ||
| from fastapi import Body, HTTPException, Query, status | ||
| from fastapi import Body, Depends, HTTPException, Query, status | ||
| from pydantic import JsonValue | ||
| from sqlalchemy import func, or_, tuple_, update | ||
| from sqlalchemy.exc import NoResultFound, SQLAlchemyError | ||
| from sqlalchemy.orm import joinedload | ||
| from sqlalchemy.sql import select | ||
| from structlog.contextvars import bind_contextvars | ||
| from airflow.api_fastapi.common.dagbag import DagBagDep | ||
| from airflow.api_fastapi.common.dagbag import dag_bag_from_app | ||
| from airflow.api_fastapi.common.db.common import SessionDep | ||
| from airflow.api_fastapi.common.types import UtcDateTime | ||
| from airflow.api_fastapi.execution_api.datamodels.taskinstance import ( | ||
| @@ -76,6 +76,9 @@ | ||
| from airflow.models.expandinput import SchedulerExpandInput | ||
| from airflow.sdk.types import Operator | ||
| from airflow.jobs.scheduler_job_runner import SchedulerDagBag | ||
| SchedulerDagBagDep = Annotated[SchedulerDagBag, Depends(dag_bag_from_app)] | ||
jason810496 marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| router = VersionedAPIRouter() | ||
| @@ -104,7 +107,7 @@ def ti_run( | ||
| task_instance_id: UUID, | ||
| ti_run_payload: Annotated[TIEnterRunningPayload, Body()], | ||
| session: SessionDep, | ||
| dag_bag: DagBagDep, | ||
| dag_bag: SchedulerDagBagDep, | ||
| ) -> TIRunContext: | ||
| """ | ||
| Run a TaskInstance. | ||
| @@ -255,7 +258,7 @@ def ti_run( | ||
| or 0 | ||
| ) | ||
| if dag := dag_bag.get_dag(ti.dag_id): | ||
| if dag := dag_bag.get_dag(dag_run=dr, session=session): | ||
| upstream_map_indexes = dict( | ||
| _get_upstream_map_indexes(dag.get_task(ti.task_id), ti.map_index, ti.run_id, session) | ||
| ) | ||
| @@ -330,7 +333,7 @@ def ti_update_state( | ||
| task_instance_id: UUID, | ||
| ti_patch_payload: Annotated[TIStateUpdate, Body()], | ||
| session: SessionDep, | ||
| dag_bag: DagBagDep, | ||
| dag_bag: SchedulerDagBagDep, | ||
| ): | ||
| """ | ||
| Update the state of a TaskInstance. | ||
| @@ -417,8 +420,9 @@ def ti_update_state( | ||
| ) | ||
| def _handle_fail_fast_for_dag(ti: TI, dag_id: str, session: SessionDep, dag_bag: DagBagDep) -> None: | ||
| ser_dag = dag_bag.get_dag(dag_id) | ||
| def _handle_fail_fast_for_dag(ti: TI, dag_id: str, session: SessionDep, dag_bag: SchedulerDagBagDep) -> None: | ||
| dr = ti.dag_run | ||
| ser_dag = dag_bag.get_dag(dag_run=dr, session=session) | ||
| if ser_dag and getattr(ser_dag, "fail_fast", False): | ||
| task_dict = getattr(ser_dag, "task_dict") | ||
| task_teardown_map = {k: v.is_teardown for k, v in task_dict.items()} | ||
| @@ -432,7 +436,7 @@ def _create_ti_state_update_query_and_update_state( | ||
| query: Update, | ||
| updated_state, | ||
| session: SessionDep, | ||
| dag_bag: DagBagDep, | ||
| dag_bag: SchedulerDagBagDep, | ||
| dag_id: str, | ||
| ) -> tuple[Update, TaskInstanceState]: | ||
| if isinstance(ti_patch_payload, (TITerminalStatePayload, TIRetryStatePayload, TISuccessStatePayload)): | ||
| @@ -893,7 +897,7 @@ def _get_group_tasks(dag_id: str, task_group_id: str, session: SessionDep, logic | ||
| def validate_inlets_and_outlets( | ||
| task_instance_id: UUID, | ||
| session: SessionDep, | ||
| dag_bag: DagBagDep, | ||
| dag_bag: SchedulerDagBagDep, | ||
| ) -> InactiveAssetsResponse: | ||
| """Validate whether there're inactive assets in inlets and outlets of a given task instance.""" | ||
| ti_id_str = str(task_instance_id) | ||
| @@ -911,7 +915,8 @@ def validate_inlets_and_outlets( | ||
| ) | ||
| if not ti.task: | ||
| dag = dag_bag.get_dag(ti.dag_id) | ||
| dr = ti.dag_run | ||
| dag = dag_bag.get_dag(dag_run=dr, session=session) | ||
| if dag: | ||
| with contextlib.suppress(TaskNotFound): | ||
| ti.task = dag.get_task(ti.task_id) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -131,15 +131,16 @@ def _get_dag(self, version_id: str, session: Session) -> DAG | None: | ||
| return dag | ||
| @staticmethod | ||
| def _version_from_dag_run(dag_run, session): | ||
| if dag_run.bundle_version: | ||
| dag_version = dag_run.created_dag_version | ||
| else: | ||
| def _version_from_dag_run(dag_run, latest, session): | ||
| if latest or not dag_run.bundle_version: | ||
| dag_version = DagVersion.get_latest_version(dag_id=dag_run.dag_id, session=session) | ||
| return dag_version | ||
| if dag_version: | ||
| return dag_version | ||
| return dag_run.created_dag_version | ||
| def get_dag(self, dag_run: DagRun, session: Session) -> DAG | None: | ||
| version = self._version_from_dag_run(dag_run=dag_run, session=session) | ||
| def get_dag(self, dag_run: DagRun, session: Session, latest=False) -> DAG | None: | ||
jedcunningham marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| version = self._version_from_dag_run(dag_run=dag_run, latest=latest, session=session) | ||
| if not version: | ||
| return None | ||
| return self._get_dag(version_id=version.id, session=session) | ||
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.