Repository: getsentry/sentry-python

Issue:
Incorrect timeout warnings when using AWS Lambda integration
sentry-sdk version: 0.17.8
AWS Lambda runtime: Python 3.8

My lambda function has a timeout of 29 seconds, but typically completes in <1s. When the lambda function is called multiple times in quick succession, the container for the lambda function is reused. When this happens, the threads that Sentry creates to manage the timeout warnings produce their warnings in subsequent function invocations (long after the function that they were created in has completed).


Discussion:
I think I have the same issue using sentry-sdk 0.18.0 and Python 3.7.9


Resolving patch:
diff --git a/sentry_sdk/integrations/aws_lambda.py b/sentry_sdk/integrations/aws_lambda.py
--- a/sentry_sdk/integrations/aws_lambda.py
+++ b/sentry_sdk/integrations/aws_lambda.py
@@ -83,6 +83,8 @@ def sentry_handler(event, context, *args, **kwargs):
                     _make_request_event_processor(event, context, configured_time)
                 )
                 scope.set_tag("aws_region", context.invoked_function_arn.split(":")[3])
+
+                timeout_thread = None
                 # Starting the Timeout thread only if the configured time is greater than Timeout warning
                 # buffer and timeout_warning parameter is set True.
                 if (
@@ -94,7 +96,8 @@ def sentry_handler(event, context, *args, **kwargs):
                     ) / MILLIS_TO_SECONDS
 
                     timeout_thread = TimeoutThread(
-                        waiting_time, configured_time / MILLIS_TO_SECONDS
+                        waiting_time,
+                        configured_time / MILLIS_TO_SECONDS,
                     )
 
                     # Starting the thread to raise timeout warning exception
@@ -116,6 +119,9 @@ def sentry_handler(event, context, *args, **kwargs):
                     )
                     hub.capture_event(event, hint=hint)
                     reraise(*exc_info)
+                finally:
+                    if timeout_thread:
+                        timeout_thread.stop()
 
     return sentry_handler  # type: ignore
 
diff --git a/sentry_sdk/integrations/gcp.py b/sentry_sdk/integrations/gcp.py
--- a/sentry_sdk/integrations/gcp.py
+++ b/sentry_sdk/integrations/gcp.py
@@ -63,6 +63,7 @@ def sentry_func(functionhandler, event, *args, **kwargs):
                     _make_request_event_processor(event, configured_time, initial_time)
                 )
                 scope.set_tag("gcp_region", environ.get("FUNCTION_REGION"))
+                timeout_thread = None
                 if (
                     integration.timeout_warning
                     and configured_time > TIMEOUT_WARNING_BUFFER
@@ -93,6 +94,8 @@ def sentry_func(functionhandler, event, *args, **kwargs):
                     hub.capture_event(event, hint=hint)
                     reraise(*exc_info)
                 finally:
+                    if timeout_thread:
+                        timeout_thread.stop()
                     # Flush out the event queue
                     hub.flush()
 
diff --git a/sentry_sdk/utils.py b/sentry_sdk/utils.py
--- a/sentry_sdk/utils.py
+++ b/sentry_sdk/utils.py
@@ -3,7 +3,6 @@
 import logging
 import os
 import sys
-import time
 import threading
 
 from datetime import datetime
@@ -891,11 +890,19 @@ def __init__(self, waiting_time, configured_timeout):
         threading.Thread.__init__(self)
         self.waiting_time = waiting_time
         self.configured_timeout = configured_timeout
+        self._stop_event = threading.Event()
+
+    def stop(self):
+        # type: () -> None
+        self._stop_event.set()
 
     def run(self):
         # type: () -> None
 
-        time.sleep(self.waiting_time)
+        self._stop_event.wait(self.waiting_time)
+
+        if self._stop_event.is_set():
+            return
 
         integer_configured_timeout = int(self.configured_timeout)
 


Test patch: