Skip to content

Conversation

@Arunodoy18
Copy link
Contributor

SUMMARY

Fix foreign key constraint failures when running airflow db clean on the dag_version table.

Previously, cleanup logic filtered dag_version rows only based on timestamp conditions.
This allowed deletion attempts for rows still referenced by task_instance.dag_version_id,
causing foreign key constraint errors during database cleanup.

This change excludes dag_version rows that are still referenced by:

  • task_instance.dag_version_id
  • dag_run.created_dag_version_id

This ensures cleanup respects referential integrity and prevents runtime failures.


ROOT CAUSE

The cleanup query did not account for existing foreign key relationships:

  • task_instance.dag_version_id → dag_version.id (RESTRICT)
  • dag_run.created_dag_version_id → dag_version.id (SET NULL)

SOLUTION

Add filtering logic to exclude referenced dag_version rows using a subquery union of:

  • task_instance.dag_version_id
  • dag_run.created_dag_version_id

TESTING

  • Added unit tests verifying referenced dag_version rows are preserved
  • Verified unreferenced rows are cleaned correctly
  • Ran existing DB cleanup test suite
  • Verified no regressions

closes: #61390
related: #52147
related: #59474

The airflow db clean command was failing with FK constraint violations
when cleaning the dag_version table. This occurred because the cleanup
logic only checked the created_at timestamp, without verifying if
dag_version rows were still referenced by task_instance or dag_run tables.

Root cause:
- task_instance.dag_version_id has FK with ondelete=RESTRICT
- dag_run.created_dag_version_id has FK with ondelete=set null
- Cleanup tried to delete referenced dag_version rows

Solution:
- Modified _build_query() to exclude dag_version rows still referenced
  by task_instance or dag_run using NOT IN subquery
- Uses SQLAlchemy, handles NULL values, efficient for large DBs

Tests added:
- test_dag_version_cleanup_respects_task_instance_fk
- test_dag_version_cleanup_deletes_unreferenced_versions
- test_dag_version_cleanup_respects_dag_run_fk

Closes: apache#61390
Replace UNION subquery with multiple NOT IN conditions for better
cross-dialect compatibility. The UNION approach was failing in CI
across MySQL, Postgres, SQLite, and low dependency environments.

Issue: SQLAlchemy's handling of UNION within NOT IN subqueries is
inconsistent across dialects and versions.

Solution: Use two separate NOT IN conditions (one for task_instance,
one for dag_run) following the pattern used in scheduler_job_runner.py
for _remove_unreferenced_triggers.

This pattern is proven to work across all Airflow-supported databases
and SQLAlchemy versions.
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.

Error when running airflow db clean on dag_version table

1 participant