Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Avoid reporting socket errors via Sentry observer #1026

Merged
merged 1 commit into from
Nov 20, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 26 additions & 6 deletions baseplate/server/wsgi.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,17 +74,37 @@ def close_connection(self, value: bool) -> None:
self._close_connection = value

def read_requestline(self) -> str | None:
real_read_requestline = gevent.spawn(super().read_requestline)
ready = gevent.wait([self._shutdown_event, real_read_requestline], count=1)
real_read_requestline = super().read_requestline

# We can't let any exceptions (e.g. socket errors) raise to the top of
# a greenlet because they will get reported as uncaught exceptions in
# our Sentry observer, even though we handle the error. So, we catch
# any exceptions and return a tuple (result, exception) instead.
def wrapped_read_requestline() -> tuple[str | None, Exception | None]:
try:
return real_read_requestline(), None
except Exception as ex:
return None, ex

read_requestline = gevent.spawn(wrapped_read_requestline)
ready = gevent.wait([self._shutdown_event, read_requestline], count=1)

if self._shutdown_event in ready:
real_read_requestline.kill()
read_requestline.kill()
read_requestline.join()
# None triggers the base class to close the connection.
return None

ret = real_read_requestline.get()
if isinstance(ret, BaseException):
raise ret
result = read_requestline.get()

if isinstance(result, BaseException):
# This shouldn't normally happen, but can with e.g. GreenletExit if
# the greenlet is killed.
raise result

ret, ex = result
if ex:
raise ex
return ret

def handle_one_request(
Expand Down