From e0d7bb733b5db43531b1efae431669bfe9e63908 Mon Sep 17 00:00:00 2001 From: Armin Ronacher Date: Mon, 30 Oct 2023 16:36:32 +0100 Subject: [PATCH] feat: Detect interpreter in shutdown state on thread spawn (#2468) This detects if the interpreter is already in shutdown state and no longer spawns a background thread. --------- Co-authored-by: Anton Pirker --- sentry_sdk/metrics.py | 19 +++++++++++++------ sentry_sdk/worker.py | 10 ++++++++-- 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/sentry_sdk/metrics.py b/sentry_sdk/metrics.py index 5230391f9e..bc91fb9fb7 100644 --- a/sentry_sdk/metrics.py +++ b/sentry_sdk/metrics.py @@ -332,18 +332,27 @@ def __init__( self._ensure_thread() def _ensure_thread(self): - # type: (...) -> None + # type: (...) -> bool """For forking processes we might need to restart this thread. This ensures that our process actually has that thread running. """ + if not self._running: + return False pid = os.getpid() if self._flusher_pid == pid: - return + return True with self._lock: self._flusher_pid = pid self._flusher = Thread(target=self._flush_loop) self._flusher.daemon = True - self._flusher.start() + try: + self._flusher.start() + except RuntimeError: + # Unfortunately at this point the interpreter is in a start that no + # longer allows us to spawn a thread and we have to bail. + self._running = False + return False + return True def _flush_loop(self): # type: (...) -> None @@ -400,9 +409,7 @@ def add( timestamp=None, # type: Optional[float] ): # type: (...) -> None - self._ensure_thread() - - if self._flusher is None: + if not self._ensure_thread() or self._flusher is None: return if timestamp is None: diff --git a/sentry_sdk/worker.py b/sentry_sdk/worker.py index 2fe81a8d70..02628b9b29 100644 --- a/sentry_sdk/worker.py +++ b/sentry_sdk/worker.py @@ -67,8 +67,14 @@ def start(self): target=self._target, name="raven-sentry.BackgroundWorker" ) self._thread.daemon = True - self._thread.start() - self._thread_for_pid = os.getpid() + try: + self._thread.start() + self._thread_for_pid = os.getpid() + except RuntimeError: + # At this point we can no longer start because the interpreter + # is already shutting down. Sadly at this point we can no longer + # send out events. + self._thread = None def kill(self): # type: () -> None