Skip to content

Commit e76614d

Browse files
committed
Retry uv pip install on cargo-related transient failures
1 parent 15cf396 commit e76614d

1 file changed

Lines changed: 55 additions & 7 deletions

File tree

scripts/in_container/install_airflow_and_providers.py

Lines changed: 55 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,9 @@
2222
import os
2323
import re
2424
import shutil
25+
import subprocess
2526
import sys
27+
import time
2628
from functools import cache
2729
from pathlib import Path
2830
from typing import NamedTuple
@@ -1117,6 +1119,50 @@ def install_airflow_and_providers(
11171119
console.print("\n[green]Done!")
11181120

11191121

1122+
def _run_uv_install_with_retry(
1123+
cmd: list[str],
1124+
github_actions: bool,
1125+
check: bool = True,
1126+
max_attempts: int = 3,
1127+
sleep_seconds: int = 30,
1128+
) -> subprocess.CompletedProcess:
1129+
"""Run a uv pip install command with retry logic for cargo-related transient failures.
1130+
1131+
Workaround for https://github.com/astral-sh/uv/issues/18801 — uv can fail with cargo-related
1132+
errors during package builds. When a failure contains "cargo" or "maturin" in the output, we retry up to
1133+
max_attempts times. Non-cargo failures are returned immediately without retry.
1134+
"""
1135+
for attempt in range(1, max_attempts + 1):
1136+
console.print(f"[bright_blue]Attempt {attempt} of {max_attempts} for uv install")
1137+
result = run_command(
1138+
cmd,
1139+
github_actions=github_actions,
1140+
check=False,
1141+
stdout=subprocess.PIPE,
1142+
stderr=subprocess.STDOUT,
1143+
)
1144+
output = result.stdout.decode() if result.stdout else ""
1145+
if output:
1146+
console.print(output)
1147+
if result.returncode == 0:
1148+
return result
1149+
if "cargo" not in output and "maturin" not in output:
1150+
console.print("[yellow]Failure is not cargo-related, not retrying.")
1151+
if check:
1152+
sys.exit(result.returncode)
1153+
return result
1154+
if attempt < max_attempts:
1155+
console.print(
1156+
f"[yellow]Attempt {attempt} failed with cargo-related error. Sleeping {sleep_seconds}s before retry..."
1157+
)
1158+
time.sleep(sleep_seconds)
1159+
else:
1160+
console.print(f"[red]All {max_attempts} attempts failed.")
1161+
if check:
1162+
sys.exit(result.returncode)
1163+
return result
1164+
1165+
11201166
def _install_airflow_and_optionally_providers_together(
11211167
installation_spec: InstallationSpec, github_actions: bool
11221168
):
@@ -1161,15 +1207,17 @@ def _install_airflow_and_optionally_providers_together(
11611207
)
11621208
install_providers_command.extend(["--constraint", installation_spec.provider_constraints_location])
11631209
console.print()
1164-
result = run_command(install_providers_command, github_actions=github_actions, check=False)
1210+
result = _run_uv_install_with_retry(
1211+
install_providers_command, github_actions=github_actions, check=False
1212+
)
11651213
if result.returncode != 0:
11661214
console.print(
11671215
"[warning]Installation with constraints failed - might be because pre-installed provider"
11681216
" has conflicting dependencies in PyPI. Falling back to a non-constraint installation."
11691217
)
1170-
run_command(base_install_cmd, github_actions=github_actions, check=True)
1218+
_run_uv_install_with_retry(base_install_cmd, github_actions=github_actions, check=True)
11711219
else:
1172-
run_command(base_install_cmd, github_actions=github_actions, check=True)
1220+
_run_uv_install_with_retry(base_install_cmd, github_actions=github_actions, check=True)
11731221

11741222

11751223
def _install_airflow_ctl_with_constraints(installation_spec: InstallationSpec, github_actions: bool):
@@ -1192,13 +1240,13 @@ def _install_airflow_ctl_with_constraints(installation_spec: InstallationSpec, g
11921240
console.print(f"[bright_blue]Use constraints: {installation_spec.airflow_ctl_constraints_location}")
11931241
install_airflow_ctl_cmd.extend(["--constraint", installation_spec.airflow_ctl_constraints_location])
11941242
console.print()
1195-
result = run_command(install_airflow_ctl_cmd, github_actions=github_actions, check=True)
1243+
result = _run_uv_install_with_retry(install_airflow_ctl_cmd, github_actions=github_actions, check=False)
11961244
if result.returncode != 0:
11971245
console.print(
11981246
"[warning]Installation with constraints failed - might be because there are"
11991247
" conflicting dependencies in PyPI. Falling back to a non-constraint installation."
12001248
)
1201-
run_command(base_install_airflow_ctl_cmd, github_actions=github_actions, check=True)
1249+
_run_uv_install_with_retry(base_install_airflow_ctl_cmd, github_actions=github_actions, check=True)
12021250

12031251

12041252
def _install_only_airflow_airflow_core_task_sdk_with_constraints(
@@ -1247,13 +1295,13 @@ def _install_only_airflow_airflow_core_task_sdk_with_constraints(
12471295
console.print(f"[bright_blue]Use constraints: {installation_spec.airflow_constraints_location}")
12481296
install_airflow_cmd.extend(["--constraint", installation_spec.airflow_constraints_location])
12491297
console.print()
1250-
result = run_command(install_airflow_cmd, github_actions=github_actions, check=False)
1298+
result = _run_uv_install_with_retry(install_airflow_cmd, github_actions=github_actions, check=False)
12511299
if result.returncode != 0:
12521300
console.print(
12531301
"[warning]Installation with constraints failed - might be because pre-installed provider"
12541302
" has conflicting dependencies in PyPI. Falling back to a non-constraint installation."
12551303
)
1256-
run_command(base_install_airflow_cmd, github_actions=github_actions, check=True)
1304+
_run_uv_install_with_retry(base_install_airflow_cmd, github_actions=github_actions, check=True)
12571305

12581306

12591307
if __name__ == "__main__":

0 commit comments

Comments
 (0)