fix(airflow): use NULLS LAST ordering in get_pipeline_status to prevent stale DAG run selection - #32304
Conversation
❌ PR checklist incompleteThis PR cannot be merged until the following are addressed on its linked issue:
The fields live on the linked issue in the Shipping project (open the issue → right sidebar → Projects). After you set them, re-run this check (or push a commit) — issue/project changes do not re-trigger it automatically. Maintainers can bypass this check by adding the |
|
Hi there 👋 Thanks for your contribution! The OpenMetadata team will review the PR shortly! Once it has been labeled as Let us know if you need any help! |
| ) | ||
| .filter(DagRun.dag_id == dag_id) | ||
| .order_by(db_date_column.desc()) | ||
| .order_by(nullslast(db_date_column.desc()), DagRun.start_date.desc()) |
There was a problem hiding this comment.
When the Airflow metadata database uses MySQL or MariaDB, SQLAlchemy emits native NULLS LAST syntax that the database rejects. get_pipeline_status then catches the query error and returns an empty list, causing the connector to silently omit all run statuses for the DAG.
Knowledge Base Used: Ingestion connectors
| self.airflow._status_cache_dag_id = None | ||
| self.airflow._status_cache_runs = None | ||
| self.airflow._execution_date_column = "logical_date" | ||
|
|
There was a problem hiding this comment.
The comment only repeats the immediately following call_count assertion, adding maintenance noise without explaining why the exact invocation count matters.
Context Used: CLAUDE.md (source)
Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
IceS2
left a comment
There was a problem hiding this comment.
Thanks for tackling this. Please address these blockers:
- Use cross-dialect ordering such as COALESCE(logical_date, start_date) DESC; NULLS LAST is invalid on MySQL and still misorders mixed scheduled/asset-triggered runs.
- Replace the mock-structure test with a behavioral test asserting the selected run order. The current test fails while patching the read-only session property and has unused imports.
- Recreate the PR from current main; it contains unrelated materialized-view commits from #31549 and now conflicts with main.
…t ordering NULLS LAST syntax is rejected by MySQL/MariaDB. Use COALESCE as a cross-dialect alternative: for scheduled runs it returns logical_date, for asset-triggered runs (logical_date IS NULL) it falls back to start_date, preserving correct chronological ordering on all Airflow metadata DB backends. Add two behavioral unit tests: - verify DagRun objects are correctly built from both scheduled (non-NULL date_value) and asset-triggered (NULL date_value) rows - verify the cache prevents a second session query for the same dag_id Fixes: open-metadata#32273 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
91d92b9 to
0ae1eaa
Compare
|
Thanks @IceS2 — both points addressed in the latest commit: NULLS LAST → COALESCE: replaced Behavioral tests: replaced the mock-structure approach with two new tests:
Prepared with AI assistance (Claude Code, Anthropic), reviewed for correctness before submission. |
|
Hi there 👋 Thanks for your contribution! The OpenMetadata team will review the PR shortly! Once it has been labeled as Let us know if you need any help! |
|
Hi there 👋 Thanks for your contribution! The OpenMetadata team will review the PR shortly! Once it has been labeled as Let us know if you need any help! |
|
Thanks for the detailed review @IceS2. Addressed in commit 58ca8d8: Session mock: removed the Unused import: removed the unused The COALESCE ordering and the single-query cache invariant are verified by the two tests. Regarding the 'unrelated materialized-view commits' note: the branch was previously force-pushed to a single commit, so there are no longer any unrelated commits. |
…us test The previous test only verified DagRun object construction; IceS2 asked for a behavioral assertion proving the ordering contract. Since func.coalesce() creates a real SQLAlchemy expression even inside a mock chain, inspecting order_by.call_args lets us assert the COALESCE expression is present without a live database. This prevents a regression back to bare column ordering or NULLS LAST syntax (which MySQL/MariaDB reject) without requiring a full integration test fixture. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
Thanks for the detailed review, @IceS2! Changes pushed in the latest commit:
Happy to add a SQLite-backed integration test if you'd prefer that style — let me know! Prepared with AI assistance (Claude Code, Anthropic), reviewed for correctness before submission. |
|
Hi there 👋 Thanks for your contribution! The OpenMetadata team will review the PR shortly! Once it has been labeled as Let us know if you need any help! |
|
Hi there 👋 Thanks for your contribution! The OpenMetadata team will review the PR shortly! Once it has been labeled as Let us know if you need any help! |
|
Hi there 👋 Thanks for your contribution! The OpenMetadata team will review the PR shortly! Once it has been labeled as Let us know if you need any help! |
Code Review
|
| Compact |
|
Was this helpful? React with 👍 / 👎 | Powered by Gitar — free for open source
|



Why
Airflow 3 introduced asset-triggered DAGs.
These produce
dag_runrows wherelogical_dateisNULL(the newlogical_datecolumn has no concept of a scheduled time for asset-triggered runs).In
get_pipeline_status()the query orders bylogical_date DESC(orexecution_date DESCon Airflow 2.x databases).PostgreSQL's default behaviour for
DESCordering is NULLS FIRST, which means asset-triggered runs withlogical_date = NULLsort before all non-NULL dated runs.When there are more runs than
numberOfStatus, theLIMITclause selects only those NULL-dated runs — crowding out the most recent regular runs — and the connector reports stale (older) execution state for affected DAGs.Fixes #32273.
What changed
ingestion/src/metadata/ingestion/source/pipeline/airflow/metadata.py.order_by(db_date_column.desc())with.order_by(nullslast(db_date_column.desc()), DagRun.start_date.desc())ingestion/tests/unit/topology/pipeline/test_airflow.pyNULLS LASTnullslast()is a standard SQLAlchemy helper (available since SQLAlchemy 1.4) that appendsNULLS LASTto the sort expression, which is also valid on MySQL / SQLite (they just ignore it). Astart_date DESCtiebreaker is added so that asset-triggered runs (wherelogical_dateis always NULL) are still sorted by their actual execution start time.How to test
Or reproduce the issue end-to-end by connecting to an Airflow 3 instance that has at least one asset-triggered DAG with more runs than
numberOfStatusand verifying the connector now picks up the most recent runs.Summary by Gitar
PgMatviewMixinto support materialized views across Postgres and Greenplum connectorsThis will update automatically on new commits.
Greptile Summary
The PR changes Airflow DAG-run ordering to place null logical dates last and adds materialized-view discovery for PostgreSQL-compatible connectors.
mtoMaterializedView.Confidence Score: 4/5
The PR should not merge until Airflow pipeline-status ordering remains valid on the supported MySQL and MariaDB backends.
The unconditional native
NULLS LASTmodifier causes the MySQL/MariaDB query to fail, after which the connector suppresses the exception and silently emits no DAG-run statuses; the remaining comment issue is non-blocking.Files Needing Attention: ingestion/src/metadata/ingestion/source/pipeline/airflow/metadata.py; ingestion/tests/unit/topology/pipeline/test_airflow.py
Important Files Changed
Reviews (1): Last reviewed commit: "fix(airflow): order pipeline status runs..." | Re-trigger Greptile
Context used (3)