Skip to content

Commit 19fcd23

Browse files
committed
Speed-up constraints generation (apache#52449)
Constraints generation was slow because we run them in a loop and we tried to run them all on a single machine - trying to utilize the fact that we only have to build airflow and provider packages once. But those are pretty fast, comparing to constraint generation and it's much better to parallelize the constraint jobs and run them on separatae workers. This will speed up constraint generation delays that will allow building PROD images and kubernetes checks faster.
1 parent fd6cedf commit 19fcd23

10 files changed

Lines changed: 77 additions & 98 deletions

File tree

.github/actions/breeze/action.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ runs:
4141
- name: "Install Breeze"
4242
shell: bash
4343
run: ./scripts/ci/install_breeze.sh
44+
env:
45+
PYTHON_VERSION: ${{ inputs.python-version }}
4446
- name: "Free space"
4547
shell: bash
4648
run: breeze ci free-space

.github/workflows/ci.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,7 @@ jobs:
225225
permissions:
226226
contents: read
227227
packages: write
228+
id-token: write
228229
if: needs.build-info.outputs.canary-run == 'true'
229230
with:
230231
runs-on-as-json-default: ${{ needs.build-info.outputs.runs-on-as-json-default }}
@@ -252,6 +253,8 @@ jobs:
252253
with:
253254
runs-on-as-json-public: ${{ needs.build-info.outputs.runs-on-as-json-public }}
254255
python-versions-list-as-string: ${{ needs.build-info.outputs.python-versions-list-as-string }}
256+
python-versions: ${{ needs.build-info.outputs.python-versions }}
257+
generate-pypi-constraints: "true"
255258
# generate no providers constraints only in canary builds - they take quite some time to generate
256259
# they are not needed for regular builds, they are only needed to update constraints in canaries
257260
generate-no-providers-constraints: ${{ needs.build-info.outputs.canary-run }}

.github/workflows/finalize-tests.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ jobs:
118118
- name: "Download constraints from the constraints generated by build CI image"
119119
uses: actions/download-artifact@v4
120120
with:
121-
name: constraints
121+
pattern: constraints-*
122122
path: ./files
123123
- name: "Diff in constraints for Python: ${{ inputs.python-versions-list-as-string }}"
124124
run: ./scripts/ci/constraints/ci_diff_constraints.sh

.github/workflows/generate-constraints.yml

Lines changed: 46 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@ on: # yamllint disable-line rule:truthy
2828
description: "Stringified array of all Python versions to test - separated by spaces."
2929
required: true
3030
type: string
31+
python-versions:
32+
description: "JSON-formatted array of Python versions to generate constraints for"
33+
required: true
34+
type: string
3135
generate-no-providers-constraints:
3236
description: "Whether to generate constraints without providers (true/false)"
3337
required: true
@@ -36,6 +40,10 @@ on: # yamllint disable-line rule:truthy
3640
description: "Space-separated list of providers that should be installed from context files"
3741
required: true
3842
type: string
43+
generate-pypi-constraints:
44+
description: "Whether to generate PyPI constraints (true/false)"
45+
required: true
46+
type: string
3947
debug-resources:
4048
description: "Whether to run in debug mode (true/false)"
4149
required: true
@@ -45,19 +53,22 @@ on: # yamllint disable-line rule:truthy
4553
required: true
4654
type: string
4755
jobs:
48-
generate-constraints:
56+
generate-constraints-matrix:
4957
permissions:
5058
contents: read
5159
timeout-minutes: 70
52-
name: Generate constraints ${{ inputs.python-versions-list-as-string }}
60+
name: Generate constraints for ${{ inputs.python-versions-list-as-string }}
5361
runs-on: ${{ fromJSON(inputs.runs-on-as-json-public) }}
62+
strategy:
63+
matrix:
64+
python-version: ${{ fromJson(inputs.python-versions) }}
5465
env:
5566
DEBUG_RESOURCES: ${{ inputs.debug-resources }}
5667
GITHUB_REPOSITORY: ${{ github.repository }}
5768
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
5869
GITHUB_USERNAME: ${{ github.actor }}
5970
INCLUDE_SUCCESS_OUTPUTS: "true"
60-
PYTHON_VERSIONS: ${{ inputs.python-versions-list-as-string }}
71+
PYTHON_VERSION: ${{ matrix.python-version }}
6172
VERBOSE: "true"
6273
VERSION_SUFFIX_FOR_PYPI: "dev0"
6374
steps:
@@ -68,70 +79,56 @@ jobs:
6879
uses: actions/checkout@v4
6980
with:
7081
persist-credentials: false
71-
- name: "Cleanup docker"
72-
run: ./scripts/ci/cleanup_docker.sh
73-
shell: bash
74-
- name: "Install Breeze"
75-
uses: ./.github/actions/breeze
76-
with:
77-
use-uv: ${{ inputs.use-uv }}
78-
id: breeze
79-
- name: "Prepare all CI images: ${{ inputs.python-versions-list-as-string}}"
80-
uses: ./.github/actions/prepare_all_ci_images
82+
- name: "Prepare breeze & CI image: ${{ matrix.python-version }}"
83+
uses: ./.github/actions/prepare_breeze_and_image
8184
with:
8285
platform: "linux/amd64"
83-
python-versions-list-as-string: ${{ inputs.python-versions-list-as-string }}
84-
docker-volume-location: "" # TODO(jscheffl): Understand why it fails here and fix it
85-
- name: "Verify all CI images ${{ inputs.python-versions-list-as-string }}"
86-
run: breeze ci-image verify --run-in-parallel
86+
python: ${{ matrix.python-version }}
87+
use-uv: ${{ inputs.use-uv }}
8788
- name: "Source constraints"
8889
shell: bash
8990
run: >
90-
breeze release-management generate-constraints --run-in-parallel
91+
breeze release-management generate-constraints
9192
--airflow-constraints-mode constraints-source-providers --answer yes
93+
--python "${PYTHON_VERSION}"
9294
- name: "No providers constraints"
9395
shell: bash
9496
timeout-minutes: 25
9597
run: >
96-
breeze release-management generate-constraints --run-in-parallel
97-
--airflow-constraints-mode constraints-no-providers --answer yes --parallelism 3
98-
# The no providers constraints are only needed when we want to update constraints (in canary builds)
99-
# They slow down the start of PROD image builds so we want to only run them when needed.
98+
breeze release-management generate-constraints
99+
--airflow-constraints-mode constraints-no-providers --answer yes
100+
--python "${PYTHON_VERSION}"
100101
if: inputs.generate-no-providers-constraints == 'true'
101-
- name: "Prepare chicken-eggs provider packages"
102-
# In case of provider packages which use latest dev0 version of providers, we should prepare them
103-
# from the source code, not from the PyPI because they have apache-airflow>=X.Y.Z dependency
104-
# And when we prepare them from sources they will have apache-airflow>=X.Y.Z.dev0
102+
- name: "Prepare updated provider distributions"
105103
shell: bash
106-
env:
107-
CHICKEN_EGG_PROVIDERS: ${{ inputs.chicken-egg-providers }}
108104
run: >
109-
breeze release-management prepare-provider-packages --include-not-ready-providers
110-
--package-format wheel --version-suffix-for-pypi dev0
111-
${CHICKEN_EGG_PROVIDERS}
112-
if: inputs.chicken-egg-providers != ''
113-
- name: "PyPI constraints"
105+
breeze release-management prepare-provider-packages
106+
--include-not-ready-providers --package-format wheel
107+
if: inputs.generate-pypi-constraints == 'true'
108+
- name: "Prepare airflow distributions"
114109
shell: bash
115-
timeout-minutes: 25
116-
env:
117-
CHICKEN_EGG_PROVIDERS: ${{ inputs.chicken-egg-providers }}
118110
run: >
119-
breeze release-management generate-constraints --run-in-parallel
120-
--airflow-constraints-mode constraints --answer yes
121-
--chicken-egg-providers "${CHICKEN_EGG_PROVIDERS}" --parallelism 3
122-
- name: "Dependency upgrade summary"
111+
breeze release-management prepare-airflow-packages --distribution-format wheel
112+
if: inputs.generate-pypi-constraints == 'true'
113+
- name: "PyPI constraints"
123114
shell: bash
124-
env:
125-
PYTHON_VERSIONS: ${{ env.PYTHON_VERSIONS }}
115+
timeout-minutes: 25
126116
run: |
127-
for PYTHON_VERSION in $PYTHON_VERSIONS; do
128-
echo "Summarizing Python $PYTHON_VERSION"
129-
cat "files/constraints-${PYTHON_VERSION}"/*.md >> $GITHUB_STEP_SUMMARY || true
130-
done
117+
breeze release-management generate-constraints --airflow-constraints-mode constraints \
118+
--answer yes --python "${PYTHON_VERSION}"
119+
if: inputs.generate-pypi-constraints == 'true'
131120
- name: "Upload constraint artifacts"
132-
uses: actions/upload-artifact@v4
121+
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
133122
with:
134-
name: constraints
135-
path: ./files/constraints-*/constraints-*.txt
123+
name: constraints-${{ matrix.python-version }}
124+
path: ./files/constraints-${{ matrix.python-version }}/constraints-*.txt
136125
retention-days: 7
137126
if-no-files-found: error
127+
- name: "Dependency upgrade summary"
128+
shell: bash
129+
env:
130+
PYTHON_VERSION: ${{ matrix.python-version }}
131+
run: |
132+
echo "Summarizing Python $PYTHON_VERSION"
133+
cat "files/constraints-${PYTHON_VERSION}"/*.md >> $GITHUB_STEP_SUMMARY || true
134+
df -H

.github/workflows/prod-image-build.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,7 @@ jobs:
233233
- name: "Download constraints"
234234
uses: actions/download-artifact@v4
235235
with:
236-
name: constraints
236+
pattern: constraints-*
237237
path: ./docker-context-files
238238
- name: "Login to ghcr.io"
239239
env:

airflow/www/static/js/types/api-generated.ts

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2532,11 +2532,8 @@ export interface components {
25322532
| "dummy"
25332533
| "all_skipped"
25342534
| "always";
2535-
/**
2536-
* @description Weight rule.
2537-
* @enum {string}
2538-
*/
2539-
WeightRule: "downstream" | "upstream" | "absolute";
2535+
/** @description Weight rule. One of 'downstream', 'upstream', 'absolute', or the path of the custom priority weight strategy class. */
2536+
WeightRule: string;
25402537
/**
25412538
* @description Health status
25422539
* @enum {string|null}

dev/breeze/src/airflow_breeze/commands/release_management_commands.py

Lines changed: 17 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,6 @@
136136
run_with_pool,
137137
)
138138
from airflow_breeze.utils.path_utils import (
139-
AIRFLOW_PROVIDERS_DIR,
140139
AIRFLOW_SOURCES_ROOT,
141140
CONSTRAINTS_CACHE_DIR,
142141
DIST_DIR,
@@ -871,43 +870,23 @@ def prepare_provider_packages(
871870
get_console().print()
872871
with ci_group(f"Preparing provider package [special]{provider_id}"):
873872
get_console().print()
874-
new_provider_root_dir = AIRFLOW_PROVIDERS_DIR.joinpath(*provider_id.split("."))
875-
if (new_provider_root_dir / "provider.yaml").exists():
876-
get_console().print(
877-
f"[info]Provider {provider_id} is a new-style provider. "
878-
f"Skipping package generation as it is not needed for new-style providers."
879-
)
880-
cleanup_build_remnants(new_provider_root_dir)
881-
build_provider_package(
882-
provider_id=provider_id,
883-
package_format=package_format,
884-
target_provider_root_sources_path=new_provider_root_dir,
885-
)
886-
move_built_packages_and_cleanup(
887-
new_provider_root_dir,
888-
DIST_DIR,
889-
skip_cleanup=skip_deleting_generated_files,
890-
delete_only_build_and_dist_folders=True,
891-
)
892-
else:
893-
# TODO(potiuk) - remove this once all providers are new-style
894-
target_provider_root_sources_path = copy_provider_sources_to_target(provider_id)
895-
generate_build_files(
896-
provider_id=provider_id,
897-
version_suffix=package_version,
898-
target_provider_root_sources_path=target_provider_root_sources_path,
899-
)
900-
cleanup_build_remnants(target_provider_root_sources_path)
901-
build_provider_package(
902-
provider_id=provider_id,
903-
package_format=package_format,
904-
target_provider_root_sources_path=target_provider_root_sources_path,
905-
)
906-
move_built_packages_and_cleanup(
907-
target_provider_root_sources_path,
908-
DIST_DIR,
909-
skip_cleanup=skip_deleting_generated_files,
910-
)
873+
target_provider_root_sources_path = copy_provider_sources_to_target(provider_id)
874+
generate_build_files(
875+
provider_id=provider_id,
876+
version_suffix=package_version,
877+
target_provider_root_sources_path=target_provider_root_sources_path,
878+
)
879+
cleanup_build_remnants(target_provider_root_sources_path)
880+
build_provider_package(
881+
provider_id=provider_id,
882+
package_format=package_format,
883+
target_provider_root_sources_path=target_provider_root_sources_path,
884+
)
885+
move_built_packages_and_cleanup(
886+
target_provider_root_sources_path,
887+
DIST_DIR,
888+
skip_cleanup=skip_deleting_generated_files,
889+
)
911890
except PrepareReleasePackageTagExistException:
912891
skipped_as_already_released_packages.append(provider_id)
913892
except PrepareReleasePackageWrongSetupException:

dev/breeze/src/airflow_breeze/prepare_providers/provider_packages.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
render_template,
3636
tag_exists_for_provider,
3737
)
38-
from airflow_breeze.utils.path_utils import AIRFLOW_PROVIDERS_DIR, AIRFLOW_SOURCES_ROOT
38+
from airflow_breeze.utils.path_utils import AIRFLOW_SOURCES_ROOT
3939
from airflow_breeze.utils.run_utils import run_command
4040
from airflow_breeze.utils.version_utils import is_local_package_version
4141

@@ -84,7 +84,7 @@ def copy_provider_sources_to_target(provider_id: str) -> Path:
8484
source_provider_sources_path = Path(AIRFLOW_SOURCES_ROOT / "airflow" / "providers").joinpath(
8585
*provider_id.split(".")
8686
)
87-
relative_provider_path = source_provider_sources_path.relative_to(AIRFLOW_PROVIDERS_DIR)
87+
relative_provider_path = source_provider_sources_path.relative_to(AIRFLOW_SOURCES_ROOT)
8888
target_providers_sub_folder = target_provider_root_path / relative_provider_path
8989
get_console().print(
9090
f"[info]Copying provider sources: {source_provider_sources_path} -> {target_providers_sub_folder}"

dev/breeze/src/airflow_breeze/utils/selective_checks.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1120,6 +1120,7 @@ def skip_pre_commits(self) -> str:
11201120
"check-provider-yaml-valid",
11211121
"lint-helm-chart",
11221122
"validate-operators-init",
1123+
"kubeconform",
11231124
)
11241125
)
11251126

dev/breeze/tests/test_selective_checks.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -788,7 +788,7 @@ def test_full_test_needed_when_scripts_changes(files: tuple[str, ...], expected_
788788
"docs-build": "true",
789789
"docs-list-as-string": "apache-airflow docker-stack",
790790
"full-tests-needed": "true",
791-
"skip-pre-commits": "check-airflow-provider-compatibility,check-extra-packages-references,check-provider-yaml-valid,identity,lint-helm-chart,mypy-airflow,mypy-dev,mypy-docs,mypy-providers,validate-operators-init",
791+
"skip-pre-commits": "check-airflow-provider-compatibility,check-extra-packages-references,check-provider-yaml-valid,identity,kubeconform,lint-helm-chart,mypy-airflow,mypy-dev,mypy-docs,mypy-providers,validate-operators-init",
792792
"upgrade-to-newer-dependencies": "false",
793793
"core-test-types-list-as-string": "API Always CLI Core Operators Other "
794794
"Serialization WWW",
@@ -972,7 +972,7 @@ def test_expected_output_pull_request_v2_7(
972972
"needs-helm-tests": "false",
973973
"run-tests": "true",
974974
"docs-build": "true",
975-
"skip-pre-commits": "check-airflow-provider-compatibility,check-extra-packages-references,check-provider-yaml-valid,identity,lint-helm-chart,mypy-airflow,mypy-dev,mypy-docs,mypy-providers,validate-operators-init",
975+
"skip-pre-commits": "check-airflow-provider-compatibility,check-extra-packages-references,check-provider-yaml-valid,identity,kubeconform,lint-helm-chart,mypy-airflow,mypy-dev,mypy-docs,mypy-providers,validate-operators-init",
976976
"docs-list-as-string": "apache-airflow docker-stack",
977977
"upgrade-to-newer-dependencies": "true",
978978
"core-test-types-list-as-string": "API Always CLI Core Operators Other Serialization WWW",

0 commit comments

Comments
 (0)