Separate out timeouts from other remote server issues (#645)

pull/646/head
Osma Ahvenlampi 2023-10-01 18:27:23 +03:00 zatwierdzone przez GitHub
rodzic 1e8a392e57
commit b60e807b91
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 4AEE18F83AFDEB23
3 zmienionych plików z 53 dodań i 15 usunięć

Wyświetl plik

@ -168,6 +168,24 @@ def test_fetch_actor(httpx_mock, config_system):
"url": "https://example.com/test-actor/view/", "url": "https://example.com/test-actor/view/",
}, },
) )
httpx_mock.add_response(
url="https://example.com/test-actor/collections/featured/",
json={
"type": "Collection",
"totalItems": 1,
"orderedItems": [
{
"id": "https://example.com/test-actor/posts/123456789",
"type": "Note",
"attributedTo": "https://example.com/test-actor/",
"content": "<p>Test post</p>",
"published": "2022-11-02T00:00:00Z",
"to": "as:Public",
"url": "https://example.com/test-actor/posts/123456789",
}
],
},
)
identity.fetch_actor() identity.fetch_actor()
# Verify the data arrived # Verify the data arrived

Wyświetl plik

@ -30,6 +30,7 @@ from core.uris import (
RelativeAbsoluteUrl, RelativeAbsoluteUrl,
StaticAbsoluteUrl, StaticAbsoluteUrl,
) )
from stator.exceptions import TryAgainLater
from stator.models import State, StateField, StateGraph, StatorModel from stator.models import State, StateField, StateGraph, StatorModel
from users.models.domain import Domain from users.models.domain import Domain
from users.models.system_actor import SystemActor from users.models.system_actor import SystemActor
@ -740,7 +741,11 @@ class Identity(StatorModel):
response.raise_for_status() response.raise_for_status()
except (httpx.HTTPError, ssl.SSLCertVerificationError) as ex: except (httpx.HTTPError, ssl.SSLCertVerificationError) as ex:
response = getattr(ex, "response", None) response = getattr(ex, "response", None)
if ( if isinstance(ex, httpx.TimeoutException) or (
response and response.status_code in [408, 504]
):
raise TryAgainLater() from ex
elif (
response response
and response.status_code < 500 and response.status_code < 500
and response.status_code not in [400, 401, 403, 404, 406, 410] and response.status_code not in [400, 401, 403, 404, 406, 410]
@ -793,7 +798,11 @@ class Identity(StatorModel):
response.raise_for_status() response.raise_for_status()
except (httpx.HTTPError, ssl.SSLCertVerificationError) as ex: except (httpx.HTTPError, ssl.SSLCertVerificationError) as ex:
response = getattr(ex, "response", None) response = getattr(ex, "response", None)
if ( if isinstance(ex, httpx.TimeoutException) or (
response and response.status_code in [408, 504]
):
raise TryAgainLater() from ex
elif (
response response
and response.status_code < 500 and response.status_code < 500
and response.status_code not in [401, 403, 404, 406, 410] and response.status_code not in [401, 403, 404, 406, 410]
@ -846,6 +855,8 @@ class Identity(StatorModel):
method="get", method="get",
uri=self.actor_uri, uri=self.actor_uri,
) )
except httpx.TimeoutException:
raise TryAgainLater()
except (httpx.RequestError, ssl.SSLCertVerificationError): except (httpx.RequestError, ssl.SSLCertVerificationError):
return False return False
content_type = response.headers.get("content-type") content_type = response.headers.get("content-type")
@ -854,10 +865,11 @@ class Identity(StatorModel):
return False return False
status_code = response.status_code status_code = response.status_code
if status_code >= 400: if status_code >= 400:
if status_code in [408, 504]:
raise TryAgainLater()
if status_code == 410 and self.pk: if status_code == 410 and self.pk:
# Their account got deleted, so let's do the same. # Their account got deleted, so let's do the same.
Identity.objects.filter(pk=self.pk).delete() Identity.objects.filter(pk=self.pk).delete()
if status_code < 500 and status_code not in [401, 403, 404, 406, 410]: if status_code < 500 and status_code not in [401, 403, 404, 406, 410]:
capture_message( capture_message(
f"Client error fetching actor at {self.actor_uri}: {status_code}", f"Client error fetching actor at {self.actor_uri}: {status_code}",
@ -923,18 +935,19 @@ class Identity(StatorModel):
) )
# Now go do webfinger with that info to see if we can get a canonical domain # Now go do webfinger with that info to see if we can get a canonical domain
actor_url_parts = urlparse(self.actor_uri) actor_url_parts = urlparse(self.actor_uri)
self.domain = Domain.get_remote_domain(actor_url_parts.hostname)
if self.username: if self.username:
webfinger_actor, webfinger_handle = self.fetch_webfinger( try:
f"{self.username}@{actor_url_parts.hostname}" webfinger_actor, webfinger_handle = self.fetch_webfinger(
) f"{self.username}@{actor_url_parts.hostname}"
if webfinger_handle: )
webfinger_username, webfinger_domain = webfinger_handle.split("@") if webfinger_handle:
self.username = webfinger_username webfinger_username, webfinger_domain = webfinger_handle.split("@")
self.domain = Domain.get_remote_domain(webfinger_domain) self.username = webfinger_username
else: self.domain = Domain.get_remote_domain(webfinger_domain)
self.domain = Domain.get_remote_domain(actor_url_parts.hostname) except TryAgainLater:
else: # continue with original domain when webfinger times out
self.domain = Domain.get_remote_domain(actor_url_parts.hostname) pass
# Emojis (we need the domain so we do them here) # Emojis (we need the domain so we do them here)
for tag in get_list(document, "tag"): for tag in get_list(document, "tag"):
if tag["type"].lower() in ["toot:emoji", "emoji"]: if tag["type"].lower() in ["toot:emoji", "emoji"]:

Wyświetl plik

@ -20,6 +20,7 @@ from core.signatures import (
VerificationFormatError, VerificationFormatError,
) )
from core.views import StaticContentView from core.views import StaticContentView
from stator.exceptions import TryAgainLater
from takahe import __version__ from takahe import __version__
from users.models import Identity, InboxMessage, SystemActor from users.models import Identity, InboxMessage, SystemActor
from users.shortcuts import by_handle_or_404 from users.shortcuts import by_handle_or_404
@ -150,7 +151,13 @@ class Inbox(View):
if not identity.public_key: if not identity.public_key:
# See if we can fetch it right now # See if we can fetch it right now
identity.fetch_actor() try:
identity.fetch_actor()
except TryAgainLater:
exceptions.capture_message(
f"Inbox error: timed out fetching actor {document['actor']}"
)
return HttpResponse(status=504)
if not identity.public_key: if not identity.public_key:
exceptions.capture_message( exceptions.capture_message(