Skip to content

Commit b3f2104

Browse files
committed
Harden domain check workflow retries
1 parent d6ee6a9 commit b3f2104

1 file changed

Lines changed: 56 additions & 10 deletions

File tree

.github/workflows/check_domains.yml

Lines changed: 56 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,10 @@ on:
1616
jobs:
1717
Test:
1818
runs-on: ubuntu-latest
19+
timeout-minutes: 10
1920
strategy:
2021
fail-fast: false
22+
max-parallel: 10
2123
matrix:
2224
domain:
2325
[
@@ -70,38 +72,82 @@ jobs:
7072
- name: Check domain redirections
7173
shell: python
7274
run: |
73-
import requests
7475
import time
76+
from urllib.parse import urlparse
77+
78+
import requests
79+
from requests.adapters import HTTPAdapter
80+
from urllib3.util.retry import Retry
81+
82+
VALID_DESTINATIONS = {"ultralytics.com", "www.ultralytics.com", "yolo11.com", "www.yolo11.com"}
83+
REQUEST_TIMEOUT = (10, 20)
84+
BASE_DELAY = 5
85+
MAX_DELAY = 120
86+
USER_AGENT = (
87+
"Mozilla/5.0 (compatible; UltralyticsDomainCheck/1.0; +https://github.com/ultralytics/docs)"
88+
)
7589
76-
def check_domain_redirection(domain, prefix, max_attempts=5):
77-
"""Check if the given domain redirects correctly, with delays between retries."""
78-
valid_destinations = ["ultralytics.com", "yolo11.com"]
90+
def build_session():
91+
"""Create a session with lightweight retries for transient HTTP errors."""
92+
retry = Retry(
93+
total=2,
94+
connect=2,
95+
read=2,
96+
status=2,
97+
backoff_factor=1,
98+
status_forcelist=(429, 500, 502, 503, 504),
99+
allowed_methods=frozenset(["GET"]),
100+
raise_on_status=False,
101+
)
102+
adapter = HTTPAdapter(max_retries=retry)
103+
session = requests.Session()
104+
session.headers.update({"User-Agent": USER_AGENT})
105+
session.mount("https://", adapter)
106+
session.mount("http://", adapter)
107+
return session
108+
109+
def is_valid_destination(url):
110+
"""Check the final redirect hostname against approved destinations."""
111+
hostname = (urlparse(url).hostname or "").lower()
112+
return hostname in VALID_DESTINATIONS
113+
114+
def check_domain_redirection(domain, prefix, session, max_attempts=5):
115+
"""Check if the given domain redirects correctly, with exponential delays between retries."""
79116
url = f"https://{prefix}{domain}"
80117
print(f"\nChecking {url}")
81118
82119
for attempt in range(max_attempts):
120+
response = None
83121
try:
84122
if attempt > 0:
85-
delay = 2 ** attempt # 2, 4, 8, 16, 32 seconds...
123+
delay = min(BASE_DELAY * (2 ** attempt), MAX_DELAY) # 10, 20, 40, 80...
124+
print(f"Retrying in {delay}s (attempt {attempt + 1}/{max_attempts})")
86125
time.sleep(delay)
87126
88-
response = requests.get(url, allow_redirects=True, timeout=10)
127+
response = session.get(url, allow_redirects=True, timeout=REQUEST_TIMEOUT, stream=True)
89128
response.raise_for_status()
90129
91-
# Check if the final URL contains any of the valid destinations
92-
if any(dest in response.url for dest in valid_destinations) and response.status_code == 200:
93-
print("Success ✅")
130+
if is_valid_destination(response.url) and response.status_code == 200:
131+
print(f"Success ✅ -> {response.url}")
94132
return True
95133
134+
print(f"Unexpected final URL: {response.url} (status {response.status_code}) ❌")
135+
return False
136+
96137
except requests.RequestException as e:
97138
print(f"Error: {e}")
98139
if attempt == max_attempts - 1:
99140
print(f"Failed after {max_attempts} attempts ❌")
100141
return False
142+
finally:
143+
if response is not None:
144+
response.close()
101145
102146
return False
103147
104-
success = check_domain_redirection('${{ matrix.domain }}', '${{ matrix.prefix }}')
148+
session = build_session()
149+
success = check_domain_redirection('${{ matrix.domain }}', '${{ matrix.prefix }}', session)
150+
session.close()
105151
if not success:
106152
raise Exception(f"Domain check failed for ${{ matrix.domain }} with prefix '${{ matrix.prefix }}'")
107153

0 commit comments

Comments
 (0)