Skip to content

Python SDK Async Improvements #4692

@srothh

Description

@srothh

This issue documents where async improvements are necessary in the Python SDK. In general, async support only makes sense if there is some sort of operation that needs to "wait" while blocking, which allows the event loop to execute other async code while the waiting code is blocking. Whenever there is CPU bound sequential work, asyncifying does not make sense. However, in these cases, running the CPU bound code in a threadpool to not block the event loop can be a good choice depending on how intensive it is. The TL;DR is that the Async Transport already alleviates the primary I/O bottleneck in the core SDK.

API

capture_event, capture_message, capture_exception

These API functions all end up using the transports capture_envelope function. As the Async Transport is designed to work with the current synchronous API, no changes should be necessary here to make this async if the Async Transport is used.

flush

With the async transport, flush optionally returns an async task, to make it awaitable if the Async Transport is used. As the api method returns the result of the client method, it should also be extended to optionally return an async task, so a blocking flush can be made available in async code.

start_span, start_transaction

I have added an async context manager for this functionality, however, in my opinion, further asyncifying this is not necessary, as there is no blocking operation and span creation is handled by otel anyway in 3.0.

From what I can tell, other functions in the API are not connected with I/O / blocking work and therefore do not need async improvements. add_attachment sounds like it would block, but from my understanding it already expects the bytes of the attachment to add as a parameter and does not read a file itself.

Client

SpotlightClient

The Spotlight Client does not use the transport for its requests, and currently uses synchronous requests, which would make sense to add async support for.

Context Manager

The client has a synchronous context manager but lacks an asynchronous one. This breaks cleanup when used with the Async Transport.

Background threads

The background threads use a capture_func to capture their events. From what I can tell, currently this is always the capture_envelope from the transport. In the Async Transport, capture_envelope is designed in a way that allows background threads to also run their tasks asynchronously on the main event loop, so that should fix this issue. If reducing thread count is the goal, these background threads could technically be converted to async tasks, however that should be made optional, as running an event loop in Python is not mandatory, and running a private event loop within the SDK sounds like a bad idea.

Additional Notes

get_bytes in PayloadRef synchronously reads a file. If this is used in async context, it might make sense to offload it to a thread pool. This is used in attachments for envelopes. In particular, it might make sense to offload the compression/attachment/envelope preparation steps in the Async transport to a thread (pool).

There is a good chance I missed something or that there are mistakes, as I am still not too familiar with all parts of the SDK. If I notice anything new, I will keep updating this issue. Also, I did not look into anything relating to Integrations.

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