Closed
Description
I have an async lambda listening to S3 bucket notifications and i wanted to track the performance of downloading a large json file. Original this was a regular function that worked but later when refactoring it to yield the file pointer it failed when deployed. Nothing was found during unit testing.
What were you trying to accomplish?
Add a @tracer.capture_method
to a function that yields
a result.
Expected Behavior
Either fail the same way during testing when POWERTOOLS_TRACE_DISABLED='true'
or support generator expression
Current Behavior
Either results in a RuntimeError("generator didn't yield")
or a Task timed out
Possible Solution
Detect and support generator expression, or have a better emulation during testing which returns an error when a return
returns a generator expression.
Steps to Reproduce (for bugs)
import contextlib
import json
import tempfile
from typing import IO
import boto3
from aws_lambda_powertools import Tracer
bucket_name = "some_bucket"
key = "file.json"
tracer = Tracer()
s3 = boto3.client("s3")
@contextlib.contextmanager
def yield_without_capture() -> str:
yield "[]"
@tracer.capture_method
@contextlib.contextmanager
def yield_with_capture() -> str:
yield "[]"
@tracer.capture_method
@contextlib.contextmanager
def boto_yield_with_capture() -> IO:
with tempfile.TemporaryFile() as fp:
s3.download_fileobj(bucket_name, key, fp)
print("download complete") # Never prints
fp.seek(0)
yield fp
@contextlib.contextmanager
def boto_yield_without_capture() -> IO:
with tempfile.TemporaryFile() as fp:
s3.download_fileobj(bucket_name, key, fp)
fp.seek(0)
print("download complete")
yield fp
@tracer.capture_lambda_handler
def lambda_handler(event: dict, _):
if event["case"] == "yield_without_capture":
with yield_without_capture() as yielded_value:
result = yielded_value
if event["case"] == "yield_with_capture":
with yield_with_capture() as yielded_value:
result = yielded_value
if event["case"] == "boto_yield_without_capture":
with boto_yield_without_capture() as fp:
result = fp.read().decode("UTF-8")
if event["case"] == "boto_yield_with_capture":
with boto_yield_with_capture() as fp:
result = fp.read().decode("UTF-8") # "Task timed out after 10.01 seconds"
return {"statusCode": 200, "result": json.loads(result)}
- case
yield_without_capture
returns the expected value - case
yield_with_capture
returns aRuntimeError("generator didn't yield")
- case
boto_yield_without_capture
returns the expected value - case
boto_yield_with_capture
returns a"Task timed out after 900.01 seconds"
Environment
- Powertools version used: 1.1.2
- Packaging format (Layers, PyPi): PyPi
- AWS Lambda function runtime: Python 3.8
Metadata
Metadata
Assignees
Labels
Type
Projects
Status
Triage