dor-bernstein opened a new issue, #70614:
URL: https://github.com/apache/airflow/issues/70614

   ### Apache Airflow version
   
   3.2.0+ (observed on 3.2.2)
   
   ### What happened
   
   The scheduler intermittently stalls: `scheduler.critical_section_duration` 
climbs while scheduler CPU drops and task scheduling starves. Inspecting the 
metadata DB during a stall shows scheduler statements of the form `UPDATE dag 
SET exceeds_max_non_backfill = … WHERE dag.dag_id = …` blocked with 
`wait_event_type = Lock` / `wait_event = transactionid`, waiting on the DAG 
processor's parse transaction.
   
   ### Root cause
   
   Before 3.2, the scheduler evaluated `max_active_runs` in memory and did not 
write the `dag` row during dagrun scheduling. **#60006 ("Separate 'next dag 
run' from 'max active runs'", merge commit 
`32bc0119b408c9a37841edd021b646324a02745e`, shipped in 3.2.0)** added the 
`dag.exceeds_max_non_backfill` column (migration 
`0097_3_2_0_add_exceeds_max_runs_flag_to_dag_model`) and made the scheduler 
**write it to the `dag` row** during dagrun scheduling:
   
   - Write: 
`airflow-core/src/airflow/jobs/scheduler_job_runner.py::_set_exceeds_max_active_runs`
 (called from `_create_dag_runs` and `_start_queued_dagruns`).
   
   That write now competes with a pre-existing lock held by the DAG processor 
for the entire per-file parse transaction:
   
   - Lock: 
`airflow-core/src/airflow/dag_processing/collection.py::DagModelOperation.find_orm_dags`
 → `with_row_locks(select(DagModel) …)` i.e. `SELECT … FOR UPDATE` on every 
`dag` row for a parsed file, held through `update_dags` + serialization + 
permission sync until the transaction commits.
   
   So the scheduler's `UPDATE dag SET exceeds_max_non_backfill = …` blocks on 
the DAG processor's `FOR UPDATE`. This is amplified when a single parsed file 
defines many DAGs (e.g. dynamically generated DAGs), because that parse 
transaction can run for minutes — holding the `dag`-row locks the whole time 
and stalling the scheduler loop.
   
   ### How to reproduce it (conceptually)
   
   1. Use the FAB auth manager and generate many DAGs from a single DAG file.
   2. While the DAG processor is parsing that file (holding `SELECT … FOR 
UPDATE` on its `dag` rows), have the scheduler attempt to update 
`exceeds_max_non_backfill` for one of those DAGs.
   3. Observe the scheduler statement blocked on `Lock`/`transactionid`, and 
`critical_section_duration` rising while scheduler CPU falls.
   
   ### Suggested direction
   
   Reduce the parse transaction's `dag`-row lock hold and/or the scheduler's 
contention on it. As a partial step, per-DAG permission sync (another writer in 
the same parse transaction) can be made to honor `[fab] update_fab_perms` — 
proposed in #70589. A more complete fix would shorten/scope the `find_orm_dags` 
lock or the scheduler's `dag`-row write.
   
   ### Anything else
   
   Related: #23232 (pluggable appless security manager).
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to