memory (disco): Cache failing servers:
When a `remote-server-not-found` stanza error is received, cache the whole server, so all queries to a entity from this server will be blocked by the cache, avoiding unnecessary network requests. During cache check, full entity JID is checked first, then its server.
This commit is contained in:
parent
cc4d9b9bd8
commit
378f05ca35
1 changed files with 32 additions and 0 deletions
|
|
@ -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)
|
||||
|
|
|
|||
Loading…
Reference in a new issue