Fix mirrors hang when /status endpoint is down (#4031)
* add explicit _fetched_remote bool * Attempt 2 * Adds about 15 seconds time-out to fetch_data_from_url with 3 retries (4, 5, 6) Then fallsback to fully local list * Feedbacks: 20 -> 30 Do not return early Add debug Remove new flag 60 second timeout for reflector * Clean up install logs by hiding mirror scores behind --verbose
This commit is contained in:
parent
c1eae10e93
commit
79313c4942
|
|
@ -194,9 +194,16 @@ class Installer:
|
||||||
else:
|
else:
|
||||||
info(tr('Skipping waiting for automatic time sync (this can cause issues if time is out of sync during installation)'))
|
info(tr('Skipping waiting for automatic time sync (this can cause issues if time is out of sync during installation)'))
|
||||||
|
|
||||||
info('Waiting for automatic mirror selection (reflector) to complete.')
|
if not arch_config_handler.args.offline:
|
||||||
while self._service_state('reflector') not in ('dead', 'failed', 'exited'):
|
info('Waiting for automatic mirror selection (reflector) to complete.')
|
||||||
time.sleep(1)
|
for _ in range(60):
|
||||||
|
if self._service_state('reflector') in ('dead', 'failed', 'exited'):
|
||||||
|
break
|
||||||
|
time.sleep(1)
|
||||||
|
else:
|
||||||
|
warn('Reflector did not complete within 60 seconds, continuing anyway...')
|
||||||
|
else:
|
||||||
|
info('Skipped reflector...')
|
||||||
|
|
||||||
# info('Waiting for pacman-init.service to complete.')
|
# info('Waiting for pacman-init.service to complete.')
|
||||||
# while self._service_state('pacman-init') not in ('dead', 'failed', 'exited'):
|
# while self._service_state('pacman-init') not in ('dead', 'failed', 'exited'):
|
||||||
|
|
|
||||||
|
|
@ -389,6 +389,7 @@ class MirrorListHandler:
|
||||||
) -> None:
|
) -> None:
|
||||||
self._local_mirrorlist = local_mirrorlist
|
self._local_mirrorlist = local_mirrorlist
|
||||||
self._status_mappings: dict[str, list[MirrorStatusEntryV3]] | None = None
|
self._status_mappings: dict[str, list[MirrorStatusEntryV3]] | None = None
|
||||||
|
self._fetched_remote: bool = False
|
||||||
|
|
||||||
def _mappings(self) -> dict[str, list[MirrorStatusEntryV3]]:
|
def _mappings(self) -> dict[str, list[MirrorStatusEntryV3]]:
|
||||||
if self._status_mappings is None:
|
if self._status_mappings is None:
|
||||||
|
|
@ -412,9 +413,12 @@ class MirrorListHandler:
|
||||||
from .args import arch_config_handler
|
from .args import arch_config_handler
|
||||||
|
|
||||||
if arch_config_handler.args.offline:
|
if arch_config_handler.args.offline:
|
||||||
|
self._fetched_remote = False
|
||||||
self.load_local_mirrors()
|
self.load_local_mirrors()
|
||||||
else:
|
else:
|
||||||
if not self.load_remote_mirrors():
|
self._fetched_remote = self.load_remote_mirrors()
|
||||||
|
debug(f'load mirrors: {self._fetched_remote}')
|
||||||
|
if not self._fetched_remote:
|
||||||
self.load_local_mirrors()
|
self.load_local_mirrors()
|
||||||
|
|
||||||
def load_remote_mirrors(self) -> bool:
|
def load_remote_mirrors(self) -> bool:
|
||||||
|
|
@ -441,7 +445,15 @@ class MirrorListHandler:
|
||||||
def get_status_by_region(self, region: str, speed_sort: bool) -> list[MirrorStatusEntryV3]:
|
def get_status_by_region(self, region: str, speed_sort: bool) -> list[MirrorStatusEntryV3]:
|
||||||
mappings = self._mappings()
|
mappings = self._mappings()
|
||||||
region_list = mappings[region]
|
region_list = mappings[region]
|
||||||
return sorted(region_list, key=lambda mirror: (mirror.score, mirror.speed))
|
|
||||||
|
# Only sort if we have remote mirror data with score/speed info
|
||||||
|
# Local mirrors lack this data and can be modified manually before-hand
|
||||||
|
# Or reflector potentially ran already
|
||||||
|
if self._fetched_remote and speed_sort:
|
||||||
|
# original return
|
||||||
|
return sorted(region_list, key=lambda mirror: (mirror.score, mirror.speed))
|
||||||
|
# just return as-is without sorting?
|
||||||
|
return region_list
|
||||||
|
|
||||||
def _parse_remote_mirror_list(self, mirrorlist: str) -> dict[str, list[MirrorStatusEntryV3]]:
|
def _parse_remote_mirror_list(self, mirrorlist: str) -> dict[str, list[MirrorStatusEntryV3]]:
|
||||||
mirror_status = MirrorStatusListV3.model_validate_json(mirrorlist)
|
mirror_status = MirrorStatusListV3.model_validate_json(mirrorlist)
|
||||||
|
|
|
||||||
|
|
@ -105,10 +105,13 @@ class MirrorStatusEntryV3(BaseModel):
|
||||||
|
|
||||||
@model_validator(mode='after')
|
@model_validator(mode='after')
|
||||||
def debug_output(self) -> 'MirrorStatusEntryV3':
|
def debug_output(self) -> 'MirrorStatusEntryV3':
|
||||||
|
from ..args import arch_config_handler
|
||||||
|
|
||||||
self._hostname, *port = urllib.parse.urlparse(self.url).netloc.split(':', 1)
|
self._hostname, *port = urllib.parse.urlparse(self.url).netloc.split(':', 1)
|
||||||
self._port = int(port[0]) if port and len(port) >= 1 else None
|
self._port = int(port[0]) if port and len(port) >= 1 else None
|
||||||
|
|
||||||
debug(f'Loaded mirror {self._hostname}' + (f' with current score of {self.score}' if self.score else ''))
|
if arch_config_handler.args.verbose:
|
||||||
|
debug(f'Loaded mirror {self._hostname}' + (f' with current score of {self.score}' if self.score else ''))
|
||||||
return self
|
return self
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -121,7 +121,7 @@ def enrich_iface_types(interfaces: list[str]) -> dict[str, str]:
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
def fetch_data_from_url(url: str, params: dict[str, str] | None = None) -> str:
|
def fetch_data_from_url(url: str, params: dict[str, str] | None = None, timeout: int = 30) -> str:
|
||||||
ssl_context = ssl.create_default_context()
|
ssl_context = ssl.create_default_context()
|
||||||
ssl_context.check_hostname = False
|
ssl_context.check_hostname = False
|
||||||
ssl_context.verify_mode = ssl.CERT_NONE
|
ssl_context.verify_mode = ssl.CERT_NONE
|
||||||
|
|
@ -133,7 +133,7 @@ def fetch_data_from_url(url: str, params: dict[str, str] | None = None) -> str:
|
||||||
full_url = url
|
full_url = url
|
||||||
|
|
||||||
try:
|
try:
|
||||||
response = urlopen(full_url, context=ssl_context)
|
response = urlopen(full_url, context=ssl_context, timeout=timeout)
|
||||||
data = response.read().decode('UTF-8')
|
data = response.read().decode('UTF-8')
|
||||||
return data
|
return data
|
||||||
except URLError as e:
|
except URLError as e:
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue