Skip to content

Skip FK-referenced dag_version rows during db clean - #68339

Merged
ephraimbuddy merged 1 commit into
apache:mainfrom
astronomer:fix-db-clean-dag-version-fk-pinned-66177
Jun 14, 2026
Merged

ephraimbuddy merged 1 commit into
apache:mainfrom
astronomer:fix-db-clean-dag-version-fk-pinned-66177

Conversation

@ephraimbuddy

Copy link
Copy Markdown
Contributor

airflow db clean on the dag_version table selected old, non-latest versions for deletion regardless of whether they were still referenced. Because task_instance.dag_version_id is ON DELETE RESTRICT, deleting a version still referenced by a task instance fails the foreign key, so the command could not prune dag_version at all for any DAG with history.

Add a generic skip_if_referenced option to the cleanup table config that excludes rows still referenced by a given (table, fk_column) via a correlated NOT EXISTS, and apply it to dag_version for task_instance.dag_version_id. Cleanup now prunes only orphaned older versions and makes progress as task instances age out and are cleaned.

related: #66177


Was generative AI tooling used to co-author this PR?
  • Yes (please specify the tool below)

Generated-by: claude opus 4.8 following the guidelines

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR improves airflow db clean behavior for dag_version by preventing deletion attempts of rows that are still referenced by task_instance.dag_version_id (an ON DELETE RESTRICT FK), allowing cleanup to make progress by pruning only orphaned, older DAG versions.

Changes:

  • Add a generic skip_if_referenced (and referenced_pk_column) option to db cleanup table configuration, implemented as a correlated NOT EXISTS filter in _build_query().
  • Apply this option to dag_version to skip versions still referenced by task_instance.dag_version_id.
  • Add a unit regression test to ensure pinned dag_version rows are skipped while orphaned old versions are deleted.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
airflow-core/src/airflow/utils/db_cleanup.py Adds skip_if_referenced filtering to the cleanup query builder and configures dag_version to use it.
airflow-core/tests/unit/utils/test_db_cleanup.py Adds a regression test verifying dag_version cleanup skips FK-pinned versions but prunes orphaned old ones.

Comment thread airflow-core/src/airflow/utils/db_cleanup.py
Comment thread airflow-core/tests/unit/utils/test_db_cleanup.py Outdated
@ephraimbuddy
ephraimbuddy force-pushed the fix-db-clean-dag-version-fk-pinned-66177 branch 2 times, most recently from 5a53021 to bec56dc Compare June 10, 2026 17:04
airflow db clean on the dag_version table selected old, non-latest
versions for deletion regardless of whether they were still referenced.
Because task_instance.dag_version_id is ON DELETE RESTRICT, deleting a
version still referenced by a task instance fails the foreign key, so
the command could not prune dag_version at all for any DAG with history.

Add a generic skip_if_referenced option to the cleanup table config that
excludes rows still referenced by a given (table, fk_column) via a
correlated NOT EXISTS, and apply it to dag_version for
task_instance.dag_version_id. Cleanup now prunes only orphaned older
versions and makes progress as task instances age out and are cleaned.

related: apache#66177
@ephraimbuddy
ephraimbuddy force-pushed the fix-db-clean-dag-version-fk-pinned-66177 branch from bec56dc to 88f8fee Compare June 11, 2026 11:48
@eladkal eladkal added this to the Airflow 3.3.0 milestone Jun 12, 2026
@potiuk potiuk linked an issue Jun 14, 2026 that may be closed by this pull request
1 of 2 tasks
@ephraimbuddy
ephraimbuddy merged commit cb7c347 into apache:main Jun 14, 2026
145 checks passed
@ephraimbuddy
ephraimbuddy deleted the fix-db-clean-dag-version-fk-pinned-66177 branch June 14, 2026 10:18
pgagnon pushed a commit to pgagnon/airflow that referenced this pull request Jun 15, 2026
airflow db clean on the dag_version table selected old, non-latest
versions for deletion regardless of whether they were still referenced.
Because task_instance.dag_version_id is ON DELETE RESTRICT, deleting a
version still referenced by a task instance fails the foreign key, so
the command could not prune dag_version at all for any DAG with history.

Add a generic skip_if_referenced option to the cleanup table config that
excludes rows still referenced by a given (table, fk_column) via a
correlated NOT EXISTS, and apply it to dag_version for
task_instance.dag_version_id. Cleanup now prunes only orphaned older
versions and makes progress as task instances age out and are cleaned.

related: apache#66177
imrichardwu pushed a commit to imrichardwu/airflow that referenced this pull request Jun 16, 2026
airflow db clean on the dag_version table selected old, non-latest
versions for deletion regardless of whether they were still referenced.
Because task_instance.dag_version_id is ON DELETE RESTRICT, deleting a
version still referenced by a task instance fails the foreign key, so
the command could not prune dag_version at all for any DAG with history.

Add a generic skip_if_referenced option to the cleanup table config that
excludes rows still referenced by a given (table, fk_column) via a
correlated NOT EXISTS, and apply it to dag_version for
task_instance.dag_version_id. Cleanup now prunes only orphaned older
versions and makes progress as task instances age out and are cleaned.

related: apache#66177
dingo4dev pushed a commit to dingo4dev/airflow that referenced this pull request Jun 16, 2026
airflow db clean on the dag_version table selected old, non-latest
versions for deletion regardless of whether they were still referenced.
Because task_instance.dag_version_id is ON DELETE RESTRICT, deleting a
version still referenced by a task instance fails the foreign key, so
the command could not prune dag_version at all for any DAG with history.

Add a generic skip_if_referenced option to the cleanup table config that
excludes rows still referenced by a given (table, fk_column) via a
correlated NOT EXISTS, and apply it to dag_version for
task_instance.dag_version_id. Cleanup now prunes only orphaned older
versions and makes progress as task instances age out and are cleaned.

related: apache#66177
RulerChen pushed a commit to RulerChen/airflow that referenced this pull request Jun 16, 2026
airflow db clean on the dag_version table selected old, non-latest
versions for deletion regardless of whether they were still referenced.
Because task_instance.dag_version_id is ON DELETE RESTRICT, deleting a
version still referenced by a task instance fails the foreign key, so
the command could not prune dag_version at all for any DAG with history.

Add a generic skip_if_referenced option to the cleanup table config that
excludes rows still referenced by a given (table, fk_column) via a
correlated NOT EXISTS, and apply it to dag_version for
task_instance.dag_version_id. Cleanup now prunes only orphaned older
versions and makes progress as task instances age out and are cleaned.

related: apache#66177
ephraimbuddy added a commit that referenced this pull request Jul 14, 2026
* Fix airflow db clean hang on MySQL when delete fails (#66177)

* Rename newsfragment to match PR number

The check-newsfragment-pr-number CI job requires the newsfragment
filename to match the PR number, not the linked issue number.

* Remove newsfragment per review

* Suppress rollback errors so the original delete error propagates

* Explain why the archive table drop reuses the session connection

* Force the FK-failure path in backend regression tests via config copy

Keeps the hang-regression tests meaningful once dag_version cleanup learns
to skip FK-pinned rows (#68339).

* Guard archive-table cleanup so it can't mask the original delete error

When _do_delete unwinds from a failed DELETE, dropping the archive table in
the finally block could itself raise (e.g. a dead connection on MySQL). Python
makes a finally-raised error the top-level exception, so that cleanup error
would replace the original delete failure -- and an OperationalError from the
drop could then be downgraded to a warning by _suppress_with_logging, silently
masking the real IntegrityError. Guard the cleanup so it only propagates on the
success path; on the failure path it is logged and the original error survives.

* Update airflow-core/tests/unit/utils/test_db_cleanup.py

Co-authored-by: Ephraim Anierobi <splendidzigy24@gmail.com>

* Retry CI after provider compat startup failure

The previous run failed because the Mongo provider test fixture could not connect to its temporary mongod container. No source change is needed; this commit retriggers CI so the PR can use a fresh signal.

---------

Co-authored-by: Ephraim Anierobi <splendidzigy24@gmail.com>
Co-authored-by: Ramachandra Nalam <nalamvamsi13@gmail.com>
joshuabvarghese pushed a commit to joshuabvarghese/airflow that referenced this pull request Jul 16, 2026
* Fix airflow db clean hang on MySQL when delete fails (apache#66177)

* Rename newsfragment to match PR number

The check-newsfragment-pr-number CI job requires the newsfragment
filename to match the PR number, not the linked issue number.

* Remove newsfragment per review

* Suppress rollback errors so the original delete error propagates

* Explain why the archive table drop reuses the session connection

* Force the FK-failure path in backend regression tests via config copy

Keeps the hang-regression tests meaningful once dag_version cleanup learns
to skip FK-pinned rows (apache#68339).

* Guard archive-table cleanup so it can't mask the original delete error

When _do_delete unwinds from a failed DELETE, dropping the archive table in
the finally block could itself raise (e.g. a dead connection on MySQL). Python
makes a finally-raised error the top-level exception, so that cleanup error
would replace the original delete failure -- and an OperationalError from the
drop could then be downgraded to a warning by _suppress_with_logging, silently
masking the real IntegrityError. Guard the cleanup so it only propagates on the
success path; on the failure path it is logged and the original error survives.

* Update airflow-core/tests/unit/utils/test_db_cleanup.py

Co-authored-by: Ephraim Anierobi <splendidzigy24@gmail.com>

* Retry CI after provider compat startup failure

The previous run failed because the Mongo provider test fixture could not connect to its temporary mongod container. No source change is needed; this commit retriggers CI so the PR can use a fresh signal.

---------

Co-authored-by: Ephraim Anierobi <splendidzigy24@gmail.com>
Co-authored-by: Ramachandra Nalam <nalamvamsi13@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ForeignKeyViolation error when doing airflow db clean

4 participants