mirror of
https://github.com/zulip/zulip.git
synced 2025-11-07 07:23:22 +00:00
sentry: Add a circuit-breaker around attempts to report to Sentry.
The goal is to reduce load on Sentry if the service is timing out, and to reduce uwsgi load from long requests. This circuit-breaker is per-Django-process, so may require more than 2 failures overall before it trips, and may also "partially" trip for some (but not all) workers. Since all of this is best-effort, this is fine. Because this is only for load reduction, we only circuit-breaker on timeouts, and not unexpected HTTP response codes or the like. See also #26229, which would move all browser-submitted Sentry reporting into a single process, which would allow circuit-breaking to be more effective.
This commit is contained in:
committed by
Tim Abbott
parent
9519945dc0
commit
cdc3413a4f
@@ -3,11 +3,12 @@ import urllib
|
|||||||
from contextlib import suppress
|
from contextlib import suppress
|
||||||
|
|
||||||
import orjson
|
import orjson
|
||||||
|
from circuitbreaker import CircuitBreakerError, circuit
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.http import HttpRequest, HttpResponse
|
from django.http import HttpRequest, HttpResponse
|
||||||
from django.utils.translation import gettext as _
|
from django.utils.translation import gettext as _
|
||||||
from django.views.decorators.csrf import csrf_exempt
|
from django.views.decorators.csrf import csrf_exempt
|
||||||
from requests.exceptions import RequestException
|
from requests.exceptions import ProxyError, RequestException, Timeout
|
||||||
from sentry_sdk.integrations.logging import ignore_logger
|
from sentry_sdk.integrations.logging import ignore_logger
|
||||||
|
|
||||||
from zerver.lib.exceptions import JsonableError
|
from zerver.lib.exceptions import JsonableError
|
||||||
@@ -83,12 +84,30 @@ def sentry_tunnel(
|
|||||||
updated_body = b"".join(parts)
|
updated_body = b"".join(parts)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
SentryTunnelSession().post(
|
sentry_request(url, updated_body)
|
||||||
url=url,
|
except CircuitBreakerError:
|
||||||
data=updated_body,
|
logger.warning("Dropped a client exception due to circuit-breaking")
|
||||||
headers={"Content-Type": "application/x-sentry-envelope"},
|
|
||||||
).raise_for_status()
|
|
||||||
except RequestException as e:
|
except RequestException as e:
|
||||||
# This logger has been configured, above, to not report to Sentry
|
# This logger has been configured, above, to not report to Sentry
|
||||||
logger.exception(e)
|
logger.exception(e)
|
||||||
return HttpResponse(status=200)
|
return HttpResponse(status=200)
|
||||||
|
|
||||||
|
|
||||||
|
# Circuit-break and temporarily stop trying to report to
|
||||||
|
# Sentry if it keeps timing out. We include ProxyError in
|
||||||
|
# here because we are likely making our requests through
|
||||||
|
# Smokescreen as a CONNECT proxy, so failures from Smokescreen
|
||||||
|
# failing to connect at the TCP level will report as
|
||||||
|
# ProxyErrors.
|
||||||
|
@circuit(
|
||||||
|
failure_threshold=2,
|
||||||
|
recovery_timeout=30,
|
||||||
|
name="Sentry tunnel",
|
||||||
|
expected_exception=(ProxyError, Timeout),
|
||||||
|
)
|
||||||
|
def sentry_request(url: str, data: bytes) -> None:
|
||||||
|
SentryTunnelSession().post(
|
||||||
|
url=url,
|
||||||
|
data=data,
|
||||||
|
headers={"Content-Type": "application/x-sentry-envelope"},
|
||||||
|
).raise_for_status()
|
||||||
|
|||||||
Reference in New Issue
Block a user