Skip to content

Using @sentry_sdk.trace with concurrent futures messes up span hierarchy #4241

Open
@Swatinem

Description

@Swatinem

How do you use Sentry?

Sentry Saas (sentry.io)

Version

2.25.1

Steps to Reproduce

I am starting (calling) a bunch of futures, before I actually await them concurrently using asyncio.gather.

The code looks like this:

import asyncio
import sentry_sdk


@sentry_sdk.trace
async def foo(a):
    await asyncio.sleep(1)
    return a


@sentry_sdk.trace
async def real_main():
    futures = [foo(a) for a in range(5)]

    results = await asyncio.gather(*futures)
    print(results)


async def main():
    sentry_sdk.init(
        dsn="…",
        debug=True,
        traces_sample_rate=1.0,
    )
    with sentry_sdk.start_transaction(op="task", name="main"):
        await real_main()


if __name__ == "__main__":
    asyncio.run(main())

I might be able to work around this in this toy example by using explicit isolation_scope myself somehow.
However, my real usecase happens deep within the graphql library, somewhere here:
https://github.com/graphql-python/graphql-core/blob/416247c1d511350445c23096f9491fbef424b69b/src/graphql/execution/execute.py#L431-L470

Expected Result

I expect the futures to create sibling spans, as they are being "started" in the same caller function.

Actual Result

Instead of the calls ending up with sibling spans, they end up as parent->child spans instead.
As the first async fn has not "finished" yet when I "start" the next one, it is on the top of the span hierarchy.

Example trace: https://sentry-sdks.sentry.io/discover/trace/9f5c02338db64a91901d28c3d90541b7

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions