Skip to content
Open
Show file tree
Hide file tree
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
2 changes: 2 additions & 0 deletions sentry_sdk/integrations/aws_lambda.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,8 @@ def sentry_handler(aws_event, aws_context, *args, **kwargs):
timeout_thread = TimeoutThread(
waiting_time,
configured_time / MILLIS_TO_SECONDS,
isolation_scope=scope,
current_scope=sentry_sdk.get_current_scope(),
)

# Starting the thread to raise timeout warning exception
Expand Down
36 changes: 34 additions & 2 deletions sentry_sdk/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -1484,17 +1484,37 @@ class TimeoutThread(threading.Thread):
waiting_time and raises a custom ServerlessTimeout exception.
"""

def __init__(self, waiting_time, configured_timeout):
# type: (float, int) -> None
def __init__(
self, waiting_time, configured_timeout, isolation_scope=None, current_scope=None
):
# type: (float, int, Optional[sentry_sdk.Scope], Optional[sentry_sdk.Scope]) -> None
threading.Thread.__init__(self)
self.waiting_time = waiting_time
self.configured_timeout = configured_timeout

self.isolation_scope = isolation_scope
self.current_scope = current_scope

self._stop_event = threading.Event()

def stop(self):
# type: () -> None
self._stop_event.set()

def _capture_exception(self):
# type: () -> ExcInfo
exc_info = sys.exc_info()

client = sentry_sdk.get_client()
event, hint = event_from_exception(
exc_info,
client_options=client.options,
mechanism={"type": "threading", "handled": False},
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can the mechanism be changed?

Keeping type=threading would keep it consistent with previous behaviour.

Changing this could help us distinguish AWS lambda timeout exceptions with exceptions caught by the threading integration that are unrelated to AWS lambda timeouts.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: AWS Lambda Timeout Mechanism Inconsistency

The TimeoutThread._capture_exception method uses mechanism={"type": "threading"}. Since this thread specifically handles AWS Lambda timeouts, this is inconsistent with other AWS Lambda integrations that use mechanism={"type": "aws_lambda"}. This can lead to miscategorization of timeout exceptions in Sentry.

Fix in Cursor Fix in Web

)
sentry_sdk.capture_event(event, hint=hint)

return exc_info

def run(self):
# type: () -> None

Expand All @@ -1510,6 +1530,18 @@ def run(self):
integer_configured_timeout = integer_configured_timeout + 1

# Raising Exception after timeout duration is reached
if self.isolation_scope is not None and self.current_scope is not None:
with sentry_sdk.scope.use_isolation_scope(self.isolation_scope):
with sentry_sdk.scope.use_scope(self.current_scope):
try:
raise ServerlessTimeoutWarning(
"WARNING : Function is expected to get timed out. Configured timeout duration = {} seconds.".format(
integer_configured_timeout
)
)
except Exception:
reraise(*self._capture_exception())

raise ServerlessTimeoutWarning(
"WARNING : Function is expected to get timed out. Configured timeout duration = {} seconds.".format(
integer_configured_timeout
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Need to add some ignore rules in this directory, because the unit tests will add the Sentry SDK and its dependencies
# into this directory to create a Lambda function package that contains everything needed to instrument a Lambda function using Sentry.

# Ignore everything
*

# But not index.py
!index.py

# And not .gitignore itself
!.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import os
import time

import sentry_sdk
from sentry_sdk.integrations.aws_lambda import AwsLambdaIntegration

sentry_sdk.init(
dsn=os.environ.get("SENTRY_DSN"),
traces_sample_rate=1.0,
integrations=[AwsLambdaIntegration(timeout_warning=True)],
)


def handler(event, context):
sentry_sdk.set_tag("custom_tag", "custom_value")
time.sleep(15)
return {
"event": event,
}
25 changes: 25 additions & 0 deletions tests/integrations/aws_lambda/test_aws_lambda.py
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,31 @@ def test_timeout_error(lambda_client, test_environment):
assert exception["mechanism"]["type"] == "threading"


def test_timeout_error_scope_modified(lambda_client, test_environment):
lambda_client.invoke(
FunctionName="TimeoutErrorScopeModified",
Payload=json.dumps({}),
)
envelopes = test_environment["server"].envelopes

(error_event,) = envelopes

assert error_event["level"] == "error"
assert (
error_event["extra"]["lambda"]["function_name"] == "TimeoutErrorScopeModified"
)

(exception,) = error_event["exception"]["values"]
assert not exception["mechanism"]["handled"]
assert exception["type"] == "ServerlessTimeoutWarning"
assert exception["value"].startswith(
"WARNING : Function is expected to get timed out. Configured timeout duration ="
)
assert exception["mechanism"]["type"] == "threading"

assert error_event["tags"]["custom_tag"] == "custom_value"


@pytest.mark.parametrize(
"aws_event, has_request_data, batch_size",
[
Expand Down