Skip to content

fix(profiling): asyncio profiling outside running loop#17165

Draft
KowalskiThomas wants to merge 2 commits intomainfrom
dd/kowalski/asyncio-profiling-non-running-loops
Draft

fix(profiling): asyncio profiling outside running loop#17165
KowalskiThomas wants to merge 2 commits intomainfrom
dd/kowalski/asyncio-profiling-non-running-loops

Conversation

@KowalskiThomas
Copy link
Copy Markdown
Contributor

Description

This fix addresses a critical bug in the asyncio profiling module where task linking and loop tracking would fail when profiling was initialized before the event loop started running. The issue occurred in two scenarios:

  1. Loop tracking: asyncio.get_running_loop() raises RuntimeError when called outside a running loop context, preventing the profiler from tracking loops that were set via asyncio.set_event_loop() but not yet running.

  2. Task linking: Direct calls to asyncio.current_task() would fail with RuntimeError in non-running contexts, breaking parent-child task relationships and loop.create_task() instrumentation.

The fix introduces safe helper functions to gracefully handle these cases:

  • _current_task_or_none(): Safely returns the current task or None instead of raising RuntimeError
  • _get_current_or_thread_loop(): Checks both running loop and thread-local policy state to recover already-set loops
  • Adds instrumentation for BaseEventLoop.create_task() to track direct loop task creation
  • All task linking calls now guard against None parent tasks

Testing

Two new test files ensure the fix works correctly:

  • tests/profiling/test__asyncio.py: Unit tests for loop tracking in non-running contexts
  • tests/profiling/collector/test_asyncio_loop_create_task.py: Integration tests for loop.create_task() instrumentation

Previously failing tests in test_asyncio_import_order.py are now enabled and passing:

  • test_asyncio_start_profiler_from_process_after_creating_loop
  • test_asyncio_import_profiler_from_process_after_starting_loop

Risks

Minimal risk. Changes are defensive and all operations are guarded with None checks. The fix only affects error paths that previously would have crashed.

Additional Notes

The implementation accesses internal asyncio event loop policy state (_local and _loop attributes) as documented in the code comments. This is necessary because asyncio.get_event_loop() would create a new loop rather than return the already-set one.


PR by Bits - View session in Datadog

Comment @DataDog to request changes

KowalskiThomas and others added 2 commits March 26, 2026 10:54
Co-authored-by: KowalskiThomas <14239160+KowalskiThomas@users.noreply.github.com>
Co-authored-by: KowalskiThomas <14239160+KowalskiThomas@users.noreply.github.com>
@datadog-official
Copy link
Copy Markdown
Contributor

View session in Datadog

Bits Dev status: ✅ Done

CI Auto-fix: Disabled | Enable

Comment @DataDog to request changes

@datadog-prod-us1-5
Copy link
Copy Markdown

I can only run on private repositories.

Base automatically changed from dd/kowalski/gevent-greenlet-untracking-keyerror to main March 27, 2026 15:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant