You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
fix: resolve asyncio event loop bug when gevent is installed (#11904)
## Description
Reverts a change
([4e31278](4e31278))
that introduced a regression in asyncio event loops when gevent is
installed. This issue cannot be reproduced on macOS; it was detected on
Ubuntu 24.
## Background
- In ddtrace v2.11.0, the ddtrace-py [introduced
support](dc000ae)
for crash tracking, and the crash tracker is started via ddtrace-run or
by importing ddtrace.auto
([here](https://github.com/DataDog/dd-trace-py/blob/main/ddtrace/auto.py)).
- Before the crash tracker is started, it [reads the agent
URL](https://github.com/DataDog/dd-trace-py/blob/v2.11.0/ddtrace/internal/core/crashtracking.py#L31)
using the
[ensure_binary](https://github.com/DataDog/dd-trace-py/blob/a58f139e24d78a66468dbc7f67ec42c2bdfad8ee/ddtrace/internal/datadog/profiling/crashtracker/_crashtracker.pyx#L50)
function.
- The ensure_binary function imports unittest.mock, which imports
[asyncio](https://github.com/DataDog/dd-trace-py/blob/v2.11.0/ddtrace/internal/compat.py#L72)
as a side effect.
- After crash tracking is started, ddtrace unloads all modules that were
imported during the setup of ddtrace features
([here](https://github.com/DataDog/dd-trace-py/blob/main/ddtrace/bootstrap/sitecustomize.py#L120C5-L120C27)).
This includes asyncio.
- At this point, asyncio has been added to and then removed from
sys.modules.
- When asyncio is imported in a user's application event loops fail to
be set. This is seen in the script below (the script was run on Ubuntu
24 with gevent>=24)
### Script
```
import asyncio
import time
loop = asyncio.get_event_loop()
loop_id = id(loop)
new_loop = asyncio.new_event_loop()
new_loop_id = id(new_loop)
print(f"old: {loop_id} new: {new_loop_id}")
asyncio.set_event_loop(new_loop)
check = asyncio.get_event_loop()
check_id = id(check)
print(f"check: {id(check)}")
while check_id != new_loop_id:
print("MISMATCH")
print(f"check: {id(check)}")
time.sleep(1)
check = asyncio.get_event_loop()
check_id = id(check)
```
### Output
```
MISMATCH
check: 131621237174144
MISMATCH
check: 131621237174144
MISMATCH
check: 131621237174144
MISMATCH
check: 131621237174144
MISMATCH
check: 131621237174144
MISMATCH
```
## Next steps
Investigate module unloading and asyncio incompatibility
## Checklist
- [x] PR author has checked that all the criteria below are met
- The PR description includes an overview of the change
- The PR description articulates the motivation for the change
- The change includes tests OR the PR description describes a testing
strategy
- The PR description notes risks associated with the change, if any
- Newly-added code is easy to change
- The change follows the [library release note
guidelines](https://ddtrace.readthedocs.io/en/stable/releasenotes.html)
- The change includes or references documentation updates if necessary
- Backport labels are set (if
[applicable](https://ddtrace.readthedocs.io/en/latest/contributing.html#backporting))
## Reviewer Checklist
- [x] Reviewer has checked that all the criteria below are met
- Title is accurate
- All changes are related to the pull request's stated goal
- Avoids breaking
[API](https://ddtrace.readthedocs.io/en/stable/versioning.html#interfaces)
changes
- Testing strategy adequately addresses listed risks
- Newly-added code is easy to change
- Release note makes sense to a user of the library
- If necessary, author has acknowledged and discussed the performance
implications of this PR as reported in the benchmarks PR comment
- Backport labels are set in a manner that is consistent with the
[release branch maintenance
policy](https://ddtrace.readthedocs.io/en/latest/contributing.html#backporting)
Copy file name to clipboardExpand all lines: .github/workflows/test_frameworks.yml
-117Lines changed: 0 additions & 117 deletions
Original file line number
Diff line number
Diff line change
@@ -111,68 +111,6 @@ jobs:
111
111
if: needs.needs-run.outputs.outcome == 'success'
112
112
run: cat debugger-expl.txt
113
113
114
-
sanic-testsuite:
115
-
strategy:
116
-
matrix:
117
-
include:
118
-
# TODO: profiling fails with a timeout error
119
-
#- suffix: Profiling
120
-
# profiling: 1
121
-
# iast: 0
122
-
# appsec: 0
123
-
- suffix: IAST
124
-
profiling: 0
125
-
iast: 1
126
-
appsec: 0
127
-
- suffix: APPSEC
128
-
profiling: 0
129
-
iast: 0
130
-
appsec: 1
131
-
- suffix: Tracer only
132
-
profiling: 0
133
-
iast: 0
134
-
appsec: 0
135
-
name: Sanic 24.6 (with ${{ matrix.suffix }})
136
-
runs-on: ubuntu-20.04
137
-
needs: needs-run
138
-
timeout-minutes: 15
139
-
env:
140
-
DD_PROFILING_ENABLED: ${{ matrix.profiling }}
141
-
DD_IAST_ENABLED: ${{ matrix.iast }}
142
-
DD_APPSEC_ENABLED: ${{ matrix.appsec }}
143
-
DD_TESTING_RAISE: true
144
-
CMAKE_BUILD_PARALLEL_LEVEL: 12
145
-
DD_DEBUGGER_EXPL_OUTPUT_FILE: debugger-expl.txt
146
-
defaults:
147
-
run:
148
-
working-directory: sanic
149
-
steps:
150
-
- uses: actions/checkout@v4
151
-
if: needs.needs-run.outputs.outcome == 'success'
152
-
with:
153
-
persist-credentials: false
154
-
path: ddtrace
155
-
- uses: actions/checkout@v4
156
-
if: needs.needs-run.outputs.outcome == 'success'
157
-
with:
158
-
persist-credentials: false
159
-
repository: sanic-org/sanic
160
-
ref: v24.6.0
161
-
path: sanic
162
-
- uses: actions/setup-python@v5
163
-
if: needs.needs-run.outputs.outcome == 'success'
164
-
with:
165
-
python-version: "3.11"
166
-
- name: Install sanic and dependencies required to run tests
167
-
if: needs.needs-run.outputs.outcome == 'success'
168
-
run: pip3 install '.[test]' aioquic
169
-
- name: Install ddtrace
170
-
if: needs.needs-run.outputs.outcome == 'success'
171
-
run: pip3 install ../ddtrace
172
-
- name: Run tests
173
-
if: needs.needs-run.outputs.outcome == 'success'
174
-
run: ddtrace-run pytest -k "not test_reloader and not test_reload_listeners and not test_no_exceptions_when_cancel_pending_request and not test_add_signal and not test_ode_removes and not test_skip_touchup and not test_dispatch_signal_triggers and not test_keep_alive_connection_context and not test_redirect_with_params and not test_keep_alive_client_timeout and not test_logger_vhosts and not test_ssl_in_multiprocess_mode"
175
-
176
114
django-testsuite:
177
115
strategy:
178
116
matrix:
@@ -963,58 +901,3 @@ jobs:
963
901
- name: Debugger exploration results
964
902
if: needs.needs-run.outputs.outcome == 'success'
965
903
run: cat debugger-expl.txt
966
-
967
-
beautifulsoup-testsuite-4_12_3:
968
-
strategy:
969
-
matrix:
970
-
include:
971
-
# TODO: profiling is disabled due to a bug in the profiler paths
0 commit comments