-
Notifications
You must be signed in to change notification settings - Fork 144
Where to put xray_recorder.configure(...AsyncContext()) in AWS Lambda functions? #203
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
Are you saying that merely adding the line to configure the What function are you decorating with In response to your question, the line
should be able to be included globally or in the lambda handler, I don't necessarily think it's causing the segment not found errors. |
Please take a look at https://github.com/stfairy/repro-xray-issue to reproduce this issue. |
Hi @stfairy, That being said, this is clearly a bug to not be able to support |
Do you actually need that to use In my tests, I simply got Code exerpt run in Python3.7 runtime import asyncio
import json
import aws_xray_sdk.core
from aws_xray_sdk.ext.aiohttp.client import aws_xray_trace_config
import aiohttp
recorder = aws_xray_sdk.core.xray_recorder
...
async def aiohttp_task():
async with aiohttp.ClientSession(trace_configs=[aws_xray_trace_config()]) as session:
async with session.get("https://httpbin.org/json") as resp:
resp = await resp.json()
print(resp)
return resp
def lambda_handler(evt, ctx):
ret = asyncio.run(aiohttp_task())
return {
"statusCode": 200,
"body": json.dumps(ret)
}
|
Hi @heitorlessa |
@willarmiros Any update on this? It prevents from using X-Ray with async code, which sounds ridiculous :) |
Hi @stfairy ! Why the error occursIn your reproduction code you first globally configure the recorder using aws-xray-sdk-python/aws_xray_sdk/core/async_context.py Lines 17 to 22 in b5b99b7
The issue is that the loop is not set as the running loop even though it is created. Later, when you use In def run(main, *, debug=None):
# ...
loop = events.new_event_loop()
try:
events.set_event_loop(loop)
# ... Finally, when the aws-xray-sdk-python/aws_xray_sdk/core/async_context.py Lines 53 to 58 in b5b99b7
SolutionsUsing
|
Hi , |
Hi @abivolmv, Sorry to hear it's not working, would you be able to provide simple reproduction code to better describe your issue? For example, I noticed that in the original description of that issue you posted, the user is trying to configure xray_recorder globally before they call I'm guessing that this would cause a similar problem to the one I pointed out above, because In def gather(*coros_or_futures, loop=None, return_exceptions=False):
...
if not coros_or_futures:
if loop is None:
# (NathanielRN): No running loop, so it makes its own which is
# not seen from previously instantiated `AsyncContext`!
loop = events.get_event_loop()
else:
warnings.warn("The loop argument is deprecated since Python 3.8, "
"and scheduled for removal in Python 3.10.",
DeprecationWarning, stacklevel=2) Hopefully there's a way you can can call the |
Hi @NathanielRN , thanks for the quick reply. I tried both solutions from above and either I see no segments and have the issue mentioned in the current description or it fails with the error mentioned in the linked issue. Some sample code would be as follows (a minimalistic state of my code): import asyncio
from io import BytesIO
import aioboto3
from aws_xray_sdk.core import xray_recorder, patch_all
from aws_xray_sdk.core.async_context import AsyncContext
# here I tried adding your solution (not added when solution to use AsyncContext() is used below)
# xray_recorder.configure(service='repro_xray_issue') # uncomment this for second solution trial
patch_all()
def lambda_handler():
asyncio.run(main())
async def main():
# here I tried adding your solution (not added when solution to remove AsyncContext() is used above)
xray_recorder.configure(service='repro_xray_issue', context=AsyncContext()) # comment this for second solution trial
async with xray_recorder.in_segment_async('my_segment_name') as segment: # comment this for second solution trial
filelike1 = BytesIO()
filelike2 = BytesIO()
res1, res2 = await asyncio.gather(s3_get(filelike1), s3_get(filelike2)) # .wait() doesn't work either
@xray_recorder.capture_async('s3_get') # tried with this and without also
async def s3_get(filelike):
async with aioboto3.Session().client('s3') as s3:
return await s3.download_fileobj('s3-bucket', 'test.txt', filelike)
if __name__ == '__main__':
lambda_handler() First solution will fail with error and second will not display the S3 segments in xray
then it works and I also see the segments in the trace. But I would like to run these calls concurrently. |
@abivolmv Thanks for providing that repro code! Actually, you understood my post exactly and this is the code I had in mind 😄 I copied your code exactly and ran it as Notice that unfortunately they do render as subsegments of subsegments instead of subsegments of the segment, but that's what we expect. You can still see them running concurrently in this image. I am running the demon locally as explained in the docs if perhaps that can be compared with how you are running it? Finally I am using:
If you see anything you are doing differently please call it out! Hopefully this helps 🙂 |
@NathanielRN I will look deeper in my code (Python 3.7, aws-xray-sdk 2.8). But in your screenshot I do not see the S3 nodes in the trace map - is that also a downside of using this solution ? |
@abivolmv Sounds good let me know how it goes! I looked into it and it looks like we do support it 🙂 Our public AWS X-Ray docs explain how to trace the context for asynchronous work. (Note that some Async libraries like So I just added this to your code: libraries = ['aioboto3']
patch(libraries) then I got S3 in the service map |
@NathanielRN
then there are no errors ever. import asyncio
from io import BytesIO
import aioboto3
from aws_xray_sdk.core import xray_recorder, patch_all
from aws_xray_sdk.core.async_context import AsyncContext
# here I tried adding your solution (not added when solution to use AsyncContext() is used below)
# xray_recorder.configure(service='repro_xray_issue') # uncomment this for second solution trial
patch_all()
def lambda_handler(a,b):
asyncio.run(main())
async def main():
# here I tried adding your solution (not added when solution to remove AsyncContext() is used above)
xray_recorder.configure(service='repro_xray_issue', context=AsyncContext()) # comment this for second solution trial
async with xray_recorder.in_segment_async('my_segment_name') as segment: # comment this for second solution trial
filelike1 = BytesIO()
filelike2 = BytesIO()
res1, res2 = await asyncio.gather(s3_get(filelike1), s3_get(filelike2)) # .wait() doesn't work either
@xray_recorder.capture_async('s3_get') # tried with this and without also
async def s3_get(filelike):
async with aioboto3.Session().client('s3') as s3:
return await s3.download_fileobj('s3-validation-files-003', 'test.txt', filelike) When it works: START RequestId: 28f14f73-5cba-4b5d-9a94-ecc36af15e98 Version: $LATEST When it doesn't: START RequestId: 2a1b8ac0-ef8b-4e3c-a3b4-b89b057524d4 Version: $LATEST |
@abivolmv Sorry for the delay in getting back to you! Thanks for providing that code, I actually had a chance to try your code out and I found that you're right it inconsistently fails and succeeds 😓 Theory of what went wrongIn my investigations I suspected that it might have something to do with our Async ContextManager: aws-xray-sdk-python/aws_xray_sdk/core/async_recorder.py Lines 13 to 14 in b5b99b7
I did some digging around and found that PEP 492 says that the I managed to avoid the "Traceback Exception" by changing the code like this: class AsyncSegmentContextManager(SegmentContextManager):
async def __aenter__(self):
return self.__enter__()
async def __aexit__(self, exc_type, exc_val, exc_tb):
async def nested():
self.__exit__(exc_type, exc_val, exc_tb)
task = await asyncio.gather(nested())
return task This way the traces show up on X-Ray but they are blank with no data in them! It seems like the code silently fails in this case instead 😕 I think our team would need time to understand just how asyncio works. Specifically, I'm suspicious that we need to find a way to "schedule the self.exit task" on the asyncio loop instead of running it immediately (so that the previous async calls using Work aroundsHowever, I noticed that if I do not patch aiobotocore, I don't get an exception. This is contrary to my expectations because I thought Either way, the custom Action ItemsWe are tracking this issue internally and once we have a chance to investigate we will get back to you! Since the question is more about using Thanks for your help with this 🙂 |
Hi, is there any update on this issue? |
Closing this in favor of #310 |
If running inside AWS Lambda, and the function is using asyncio so I need
However if I put it in the global, or in my lambda handler, I always get errors like
I think it's because Lambda has its own segment created, presumably it's the LambdaContext defined in aws_xray_sdk/core/lambda_launcher.py?
So how should I configure it properly so that @xray_recorder.capture_async can work?
The text was updated successfully, but these errors were encountered: