Eason09053360 opened a new pull request, #73154: URL: https://github.com/apache/airflow/pull/73154
## Why `DagBundlesManager.sync_bundles_to_db` runs on every Dag processor start, and resolved bundle ownership one bundle at a time: - each configured bundle with a `team_name` issued its own `SELECT ... FROM team WHERE name = ?`, repeating the query even when several bundles share a team; - building `bundle_to_team` touches `DagBundleModel.teams`, which is a default `lazy="select"` relationship, so each *stored* bundle lazy-loaded its team in a separate round-trip. Both scale with the number of configured bundles. The `stored` query a few lines above already reads all of its rows in one go, so the same function was inconsistent with itself. Measured on SQLite with 4 bundles sharing 2 teams, counting statements that read `team`: | | before | after | | --- | --- | --- | | first sync (empty `dag_bundle`) | 4 | 1 | | subsequent syncs (bundles stored) | 8 | 2 | The count is now independent of the bundle count rather than proportional to it. ## What `airflow-core/src/airflow/dag_processing/bundles/manager.py`: - eager-load `DagBundleModel.teams` with `selectinload` on the `stored` query, so `bundle_to_team` reads an already-populated relationship; - collect the configured team names into a set and fetch them with a single `Team.name.in_(...)`, then resolve each bundle's team from that dict. `Team.name` is the primary key, so the dict lookup is equivalent to the previous `one_or_none()`. The query is skipped entirely when no bundle declares a team, which is the case for every deployment that does not enable `[core] multi_team`. The "team does not exist" check stays inside the loop and keeps its position relative to `_extract_and_sign_template`, so error behaviour is unchanged. `airflow-core/tests/unit/dag_processing/bundles/test_dag_bundle_manager.py` adds `test_sync_bundles_to_db_looks_up_teams_in_a_fixed_number_of_queries`, which counts `team` statements over two consecutive syncs — the second one covers the steady state where bundles are already stored, which is where the lazy-load path is reachable. The module's `clear_db` fixture now also clears `team`. --- ### One question for reviewers `team.name` is a plain `String`, not a `StringID`, so it does not get the `utf8mb3_bin` collation that `airflow.models.base` applies to id columns. On MySQL the old `WHERE name = ?` therefore matched case-insensitively, while the new dict lookup is exact. A bundle config carrying `"team_name": "Team-A"` against a stored `team-a` would have synced on MySQL and now raises. I did not add a case-folding fallback, because that spelling is already rejected everywhere else: `airflow teams create` and `airflow teams sync` both hold bundle-config team names to `TEAM_NAME_PATTERN` (lower case only), and migration `0131_3_4_0_lower_case_team_names` folds stored names to lower case. Keeping the leniency would make this function accept a name that `teams sync` refuses. Happy to add the fallback if you would rather not change that at all. --- ##### Was generative AI tooling used to co-author this PR? - [X] Yes — Claude Code (Opus 5) Generated-by: Claude Code (Opus 5) following [the guidelines](https://github.com/apache/airflow/blob/main/contributing-docs/05_pull_requests.rst#gen-ai-assisted-contributions) -- 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]
