serverless / dashboard

MIT License
24 stars 10 forks source link

Decorator on lambda handler causes flaky crash #839

Open fafrd opened 1 year ago

fafrd commented 1 year ago

I'm trying to use Sentry alongside Serverless and having a pretty bad time. Getting flaky failures when calling sentry_sdk.init:

[ERROR] KeyError: 'sentry_sdk.integrations.asgi'
Traceback (most recent call last):
  File "/opt/python/serverless_aws_lambda_sdk/instrument/__init__.py", line 590, in stub
    return self._handler(user_handler, event, context)
  File "/opt/python/serverless_aws_lambda_sdk/instrument/__init__.py", line 572, in _handler
    result = user_handler(event, context)
  File "/var/task/serverless_sdk/__init__.py", line 144, in wrapped_handler
    return user_handler(event, context)
  File "/var/task/lib/services/utils.py", line 22, in wrapper
    sentry_sdk.init(
  File "/var/task/sentry_sdk/hub.py", line 132, in _init
    client = Client(*args, **kwargs)  # type: ignore
  File "/var/task/sentry_sdk/client.py", line 143, in __init__
    self._init_impl()
  File "/var/task/sentry_sdk/client.py", line 223, in _init_impl
    self.integrations = setup_integrations(
  File "/var/task/sentry_sdk/integrations/__init__.py", line 110, in setup_integrations
    for integration_cls in iter_default_integrations(
  File "/var/task/sentry_sdk/integrations/__init__.py", line 41, in iter_default_integrations
    yield getattr(import_module(module), cls)
  File "/var/lang/lib/python3.8/importlib/__init__.py", line 127, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
  File "<frozen importlib._bootstrap>", line 1014, in _gcd_import
  File "<frozen importlib._bootstrap>", line 991, in _find_and_load
  File "<frozen importlib._bootstrap>", line 975, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 671, in _load_unlocked
  File "<frozen importlib._bootstrap_external>", line 843, in exec_module
  File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed
  File "/var/task/sentry_sdk/integrations/starlette.py", line 16, in <module>
    from sentry_sdk.integrations.asgi import SentryAsgiMiddleware
  File "<frozen importlib._bootstrap>", line 991, in _find_and_load
  File "<frozen importlib._bootstrap>", line 975, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 682, in _load_unlocked

Multiple different components of the library seem to cause this:

[ERROR] KeyError: 'sentry_sdk._werkzeug'
Traceback (most recent call last):
  File "/opt/python/serverless_aws_lambda_sdk/instrument/__init__.py", line 590, in stub
    return self._handler(user_handler, event, context)
[ERROR] ImportError: cannot import name 'SentryWsgiMiddleware' from 'sentry_sdk.integrations.wsgi' (/var/task/sentry_sdk/integrations/wsgi.py)
Traceback (most recent call last):
  File "/opt/python/serverless_aws_lambda_sdk/instrument/__init__.py", line 590, in stub
    return self._handler(user_handler, event, context)

point of failure is here: https://github.com/serverless/console/blob/main/python/packages/aws-lambda-sdk/serverless_aws_lambda_sdk/instrument/__init__.py#L590

fafrd commented 1 year ago

This seems to only happen on Lambda cold starts

fafrd commented 1 year ago

Ok, this is happening when I have a decorator on the Lambda handler which pulls in another library. It can be recreated like this:

    @sentry_initialize()
    def handler(event, context):
        ...
from functools import wraps

import sentry_sdk
from sentry_sdk.integrations.aws_lambda import AwsLambdaIntegration

def sentry_initialize(function_name):
    def decorator(function):
        @wraps(function)
        def wrapper(*args, **kwargs):
            sentry_sdk.init(
                dsn=SENTRY_DSN,
                debug=False,
                integrations=[
                    AwsLambdaIntegration(timeout_warning=True),
                ],
                traces_sample_rate=1.0,  # Capture all traces
            )
            sentry_sdk.set_tag("function_name", function_name)

            # then call the function
            return function(*args, **kwargs)

        return wrapper
    return decorator

When I change sentry_initialize to not be a decorator- instead call this method manually inside the module- the code works as expected.