vuonghoangbntt opened a new issue, #75666:
URL: https://github.com/apache/airflow/issues/75666

   ### Under which category would you file this issue?
   
   Airflow Core
   
   ### Apache Airflow version
   
   3.3.1
   
   ### What happened and how to reproduce it?
   
   **Issue Description**
   
   With a versioning bundle, `airflow dag-processor --num-runs N` never exits 
once it has
   handled a Dag callback.
   
   A callback for a versioned Dag run gets its own `_file_stats` entry, keyed 
with
   `bundle_version`, next to the bundle scan's entry for the same file. A 
callback-only
   parse doesn't bump `run_count` (`process_parse_results` keeps it as is), so 
that entry
   stays at 0. But `max_runs_reached` waits for every entry to reach N:
   
   ```python
   return all(stat.run_count >= self.max_runs for stat in 
self._file_stats.values())
   ```
   
   so it never returns `True`. The entry doesn't go away either: 
`remove_orphaned_file_stats`
   matches on `presence_key` and keeps it while the file exists, which is 
intended since
   #66484. The processor keeps running until something kills it.
   
   If the callback processor times out instead, `_kill_timed_out_processors` 
sets the
   entry's `run_count` to 1. That still blocks any N of 2 or more.
   
   **Steps to reproduce:**
   
   How it shows up: run `airflow dag-processor --num-runs 1` against a 
versioning bundle
   (for example `GitDagBundle`) with a Dag that has an `on_failure_callback`, 
and fail one
   of its runs while the processor is up. Once the callback has been processed, 
the
   processor keeps looping instead of exiting. I haven't run this end to end; 
the test
   below shows the same thing directly.
   
   Add this to `TestDagFileProcessorManager` in
   `airflow-core/tests/unit/dag_processing/test_manager.py`. It fails on main 
at the last
   line:
   
   ```python
   def test_num_runs_exits_after_a_dag_callback(self):
       manager = DagFileProcessorManager(max_runs=1)
       scan_file = _get_file_infos(["file_1.py"])[0]
       callback_file = _get_versioned_file_info("file_1.py")  # same file, 
bundle_version="v1"
   
       # The bundle scan has parsed the file once, so --num-runs 1 is done.
       manager._file_stats[scan_file] = DagFileStat(run_count=1, 
last_finish_time=timezone.utcnow())
       manager._num_run = 1
       assert manager.max_runs_reached()
   
       # Then a Dag callback for a run on bundle version "v1" is processed.
       processor, _ = self.mock_processor(start_time=time.monotonic() - 1)
       processor.had_callbacks = True
       processor.parsing_result = None
       manager.handle_parsing_result(callback_file, processor)
   
       assert manager.max_runs_reached()  # fails: the callback's entry has 
run_count=0
   ```
   
   ### What you think should happen instead?
   
   The processor should exit once every file has been parsed N times, whether 
or not a
   callback ran. `max_runs_reached` could check only the bundle scan's stats, 
like
   `prepare_file_queue` does after #73433, by iterating over
   `self._resolve_stats_by_presence_key().values()`.
   
   @ephraimbuddy spotted this while reviewing #73433. The fix needs the helper 
that PR adds,
   so I'll open it after #73433 is merged.
   
   
   ### Operating System
   
   _No response_
   
   ### Deployment
   
   None
   
   ### Apache Airflow Provider(s)
   
   _No response_
   
   ### Versions of Apache Airflow Providers
   
   _No response_
   
   ### Official Helm Chart version
   
   Not Applicable
   
   ### Kubernetes Version
   
   _No response_
   
   ### Helm Chart configuration
   
   _No response_
   
   ### Docker Image customizations
   
   _No response_
   
   ### Anything else?
   
   This has been there since #66484 (3.3.0). It only affects `--num-runs` with 
a versioning
   bundle. With the default (unlimited runs), `max_runs_reached` returns early, 
so nothing
   changes there.
   
   ### Are you willing to submit PR?
   
   - [x] Yes I am willing to submit a PR!
   
   ### Code of Conduct
   
   - [x] I agree to follow this project's [Code of 
Conduct](https://github.com/apache/airflow/blob/main/CODE_OF_CONDUCT.md)
   


-- 
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