diff --git a/libervia/backend/memory/disco.py b/libervia/backend/memory/disco.py index 76e73513..eeb70cd2 100755 --- a/libervia/backend/memory/disco.py +++ b/libervia/backend/memory/disco.py @@ -48,6 +48,8 @@ TIMEOUT = 15 DISCO_CACHE_TTL = 900 # Delay before retrying a failed disco query (in seconds) DISCO_RETRY_DELAY = 300 +# Delay before retrying a server that failed (in seconds) +DISCO_SERVER_RETRY_DELAY = 3600 class HashGenerationError(Exception): @@ -225,6 +227,7 @@ class Discovery: """ if jid_ is None: jid_ = jid.JID(client.jid.host) + try: if not use_cache: # we ignore cache, so we pretend we haven't found it @@ -262,6 +265,24 @@ class Discovery: log.debug(f"Disco cache expired for {jid_.full()}, re-querying") del self._jid_disco_cache[jid_] + # Entity-level cache miss or expired, check server-level cache + if use_cache and (server_jid := jid.JID(jid_.host)) in self._jid_disco_cache: + data, timestamp = self._jid_disco_cache[server_jid] + if data is None: + elapsed = time.time() - timestamp + if elapsed < DISCO_SERVER_RETRY_DELAY: + msg = ( + f"Server {server_jid} is unreachable, retry in " + f"{int(DISCO_SERVER_RETRY_DELAY - elapsed)} seconds" + ) + log.debug(msg) + return defer.fail(exceptions.ExternalRequestError(msg)) + else: + log.debug( + f"Retry delay expired for unreachable server {server_jid}" + ) + del self._jid_disco_cache[server_jid] + # No cache is used, we will do a query to return disco infos. # The query result will be cached in JID cache. query_key = (jid_, node) @@ -288,6 +309,17 @@ class Discovery: if fail.check(defer.CancelledError): reason = "request time-out" fail = failure.Failure(exceptions.TimeOutError(str(fail.value))) + elif fail.check(StanzaError): + stanza_error = fail.value + if stanza_error.condition == "remote-server-not-found": + # Mark the server as unreachable (store as domain JID) + server_jid = jid.JID(jid_.host) + self._jid_disco_cache[server_jid] = (None, time.time()) + log.warning( + f"Server {server_jid} is unreachable, will retry in " + f"{DISCO_SERVER_RETRY_DELAY} seconds" + ) + reason = str(fail.value) else: try: reason = str(fail.value)