diff --git a/CHANGES/3891.bugfix b/CHANGES/3891.bugfix new file mode 100644 index 000000000..8ce4aaa3f --- /dev/null +++ b/CHANGES/3891.bugfix @@ -0,0 +1 @@ +Added a retry mechanism for client authentication in ULN-based downloaders to improve connection stability. diff --git a/pulp_rpm/app/downloaders.py b/pulp_rpm/app/downloaders.py index 2da96808a..3ebf920bf 100644 --- a/pulp_rpm/app/downloaders.py +++ b/pulp_rpm/app/downloaders.py @@ -1,4 +1,5 @@ import os +import asyncio from aiohttp_xmlrpc.client import ServerProxy, _Method from logging import getLogger @@ -174,7 +175,7 @@ async def _run(self, extra_data=None): SERVER_URL, proxy=self.proxy, proxy_auth=self.proxy_auth, auth=self.auth ) if not self.session_key: - self.session_key = await client.auth.login(self.username, self.password) + self.session_key = await self._login_and_retry(client) if len(self.session_key) != 43: raise UlnCredentialsError() self.headers = {"X-ULN-API-User-Key": self.session_key} @@ -196,6 +197,34 @@ async def _run(self, extra_data=None): client.close() return to_return + async def _login_and_retry(self, client, max_attempts=5, delay=1): + """ + Attempts to log in using the provided client. Retries up to `max_attempts` + times with a delay between attempts. + + Args: + client: The client object used for authentication. + max_attempts (int): Maximum number of login attempts. + delay (int or float): Delay in seconds between retries. + + Returns: + The session key from the login. + + Raises: + UlnCredentialsError: If all login attempts fail. + """ + for attempt in range(1, max_attempts + 1): + try: + return await client.auth.login(self.username, self.password) + except Exception as exc: + if attempt < max_attempts: + log.info(f"ULN login attempt {attempt} failed. Retrying...") + await asyncio.sleep(delay) + else: + raise UlnCredentialsError( + f"ULN login failed after {max_attempts} attempts." + ) from exc + class AllowProxyServerProxy(ServerProxy): """