GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — fix(tracing): Find query source across the greenlet that async SQLAlchemy runs the driver in by ryanhiizy · Pull Request #8237 · getsentry/sentry-python

Conversation

@ryanhiizy

@ryanhiizy ryanhiizy commented Nov 10, 2026 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown

Description

As discussed in #8205 (thanks @sentrivana).

With async SQLAlchemy, DB spans never get query source (code.function, code.filepath, …), because add_source never finds an application frame.

SQLAlchemy's asyncio extension runs the sync driver inside a greenlet that it starts from the coroutine awaiting the query. The cursor events that create the span run in that greenlet. Walking f_back from there reaches only SQLAlchemy and greenlet frames, then stops at the greenlet's boundary, so it never sees the application code that issued the query.

When the current greenlet is SQLAlchemy's bridge, add_source now continues into the parent greenlet's suspended frames, which hold the awaiting coroutine. Other greenlets aren't followed, since a greenlet's parent isn't necessarily its caller and following it could attribute the span to unrelated code. It only reads frames, and it does nothing if greenlet isn't imported or the lookup fails.

The bridge is recognised by __sqlalchemy_greenlet_provider__, the attribute SQLAlchemy checks itself, which it sets from 1.4.53 and 2.0.31. Earlier releases don't set it, so there it is recognised by its class, _AsyncIoGreenlet from a sqlalchemy module. I checked both paths locally against 1.4.52 and 2.0.30, where the test fails without the class check.

The test runs a query through SQLAlchemy's real greenlet_spawn from a coroutine and checks the coroutine is its source, for both static and streamed spans; it fails on master.

It skips only before SQLAlchemy 1.4, not when greenlet is missing, so it fails instead of silently not running if greenlet ever drops out of the 1.4+ environments.

greenlet is only an optional extra of SQLAlchemy 2.x, and 1.4 installs it only on some platforms (not macOS arm64), so I added it to the 1.4+ test environments in scripts/populate_tox/config.py. In tox.ini I applied only the lines the generator adds for it, leaving out the 2.1.6 → 2.1.8 bump it would also make, to keep this PR scoped. Happy to commit the full regeneration instead if you prefer; a full run currently also bumps most other integrations.

With the reproduction from the issue (SQLAlchemy 2.1.6, aiosqlite):

master:  SELECT 1 -> None
this PR: SELECT 1 -> async_query

Issues

  • resolves: Query source is never set on DB spans from async SQLAlchemy #8205
  • resolves: PY-3062

Written with Claude (Opus 5.5). I reviewed the change and ran the reproduction and the SQLAlchemy 1.2, 1.4, 2.0 and 2.1 test suites locally before opening this.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
@ryanhiizy
fix(tracing): Find query source across the greenlet that async SQLAlc…
bb98b11
…hemy runs the driver in
@ryanhiizy
ryanhiizy requested a review from a team as a code owner November 10, 2026 22:03
@ryanhiizy
fix(tracing): Only follow the parent greenlet from SQLAlchemy's async…
dc44691
… bridge

A greenlet's parent is not necessarily its caller, so following any parent
could attribute a span to unrelated code. Only SQLAlchemy's bridge greenlet,
which it marks with __sqlalchemy_greenlet_provider__, is known to be spawned
by the coroutine awaiting the query.

Test through SQLAlchemy's real greenlet_spawn, add a case where an unrelated
parent gives no source, and install greenlet for the SQLAlchemy 2.x test
environments, where it is only an optional extra.
cursor[bot]
cursor Bot reviewed Nov 10, 2026
View reviewed changes

@cursor cursor Bot left a comment

Copy link
Copy Markdown

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Want fixes drafted automatically? Bugbot Autofix can create code changes for findings. A team admin can enable Autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit dc44691. Configure here.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
Comment thread sentry_sdk/tracing_utils.py Resolved

Uh oh!

There was an error while loading. Please reload this page.

ryanhiizy added 4 commits November 11, 2026 09:42
@ryanhiizy
fix(tracing): Recognise SQLAlchemy's async bridge before 1.4.53 and 2…
95dd7a3
….0.31

Earlier releases don't set __sqlalchemy_greenlet_provider__ on the bridge
greenlet, so identify it by its class there.
@ryanhiizy
test(sqlalchemy): Fail instead of skipping the async bridge tests wit…
603bd18
…hout greenlet

Skip on SQLAlchemy before 1.4 only, so the tests can't silently stop
running if greenlet drops out of the 1.4+ environments.
@ryanhiizy
test(sqlalchemy): Install greenlet in the 1.4 test environments too
ceb11ac
SQLAlchemy 1.4 only depends on greenlet on some platforms, not macOS
arm64, where the async bridge tests would otherwise fail.
@ryanhiizy
test(sqlalchemy): Keep only the async bridge regression test
cc39900

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Reviewers

@cursor cursor[bot] cursor[bot] left review comments

At least 1 approving review is required to merge this pull request.

Uh oh!

There was an error while loading. Please reload this page.

Assignees

No one assigned

Labels

None yet

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

Query source is never set on DB spans from async SQLAlchemy

Uh oh!

There was an error while loading. Please reload this page.

1 participant

@ryanhiizy
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
You are visitor 01402503 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.