Skip to content

Commit b392bc4

Browse files
BYKclaude
andcommitted
refactor: Simplify and deduplicate async transport code
Major cleanup that removes ~390 lines while preserving all functionality: Architecture: - Always define AsyncHttpTransport as a real class (not aliased to HttpTransport when deps missing). Raises RuntimeError in __init__ instead. This eliminates the isinstance aliasing bug and removes most type: ignore annotations. - Add _is_async_transport() helper to _Client, replacing 4 repeated isinstance checks. Deduplication in transport.py: - Extract _get_httpcore_pool_options() into HttpTransportCore — shared by AsyncHttpTransport and Http2Transport (SSL, certs, socket opts). - Extract _resolve_proxy() into HttpTransportCore — shared proxy URL resolution logic. - Extract _timeout_extensions property — shared timeout config dict. - Extract _get_httpcore_header_value() module function — shared case-insensitive header lookup for httpcore responses. - Enable HTTP/2 in AsyncHttpTransport when DSN scheme is HTTPS. Simplification in client.py: - Use _batchers tuple property in _flush_components/_close_components to avoid repeating the same None-check pattern for each batcher. Test cleanup: - Extract PROXY_TESTCASES and SOCKS_PROXY_TESTCASES constants shared between sync and async proxy tests (-300 lines). - Add _make_async_transport_options() helper for make_transport tests. - Remove section separator comments. - Trim Worker ABC docstrings to one-liners. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent b990610 commit b392bc4

File tree

6 files changed

+519
-909
lines changed

6 files changed

+519
-909
lines changed

sentry_sdk/client.py

Lines changed: 20 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@
3232
from sentry_sdk.tracing import trace
3333
from sentry_sdk.tracing_utils import has_span_streaming_enabled
3434
from sentry_sdk.transport import (
35-
ASYNC_TRANSPORT_ENABLED,
3635
HttpTransportCore,
3736
make_transport,
3837
AsyncHttpTransport,
@@ -1010,27 +1009,31 @@ def get_integration(
10101009

10111010
return self.integrations.get(integration_name)
10121011

1012+
def _is_async_transport(self) -> bool:
1013+
"""Check if the current transport is async."""
1014+
return isinstance(self.transport, AsyncHttpTransport)
1015+
1016+
@property
1017+
def _batchers(self) -> "tuple[Any, ...]":
1018+
return tuple(
1019+
b
1020+
for b in (self.log_batcher, self.metrics_batcher, self.span_batcher)
1021+
if b is not None
1022+
)
1023+
10131024
def _close_components(self) -> None:
10141025
"""Kill all client components in the correct order."""
10151026
self.session_flusher.kill()
1016-
if self.log_batcher is not None:
1017-
self.log_batcher.kill()
1018-
if self.metrics_batcher is not None:
1019-
self.metrics_batcher.kill()
1020-
if self.span_batcher is not None:
1021-
self.span_batcher.kill()
1027+
for b in self._batchers:
1028+
b.kill()
10221029
if self.monitor:
10231030
self.monitor.kill()
10241031

10251032
def _flush_components(self) -> None:
10261033
"""Flush all client components."""
10271034
self.session_flusher.flush()
1028-
if self.log_batcher is not None:
1029-
self.log_batcher.flush()
1030-
if self.metrics_batcher is not None:
1031-
self.metrics_batcher.flush()
1032-
if self.span_batcher is not None:
1033-
self.span_batcher.flush()
1035+
for b in self._batchers:
1036+
b.flush()
10341037

10351038
def close(
10361039
self,
@@ -1042,9 +1045,7 @@ def close(
10421045
semantics as :py:meth:`Client.flush`.
10431046
"""
10441047
if self.transport is not None:
1045-
if ASYNC_TRANSPORT_ENABLED and isinstance(
1046-
self.transport, AsyncHttpTransport
1047-
):
1048+
if self._is_async_transport():
10481049
logger.warning(
10491050
"close() used with AsyncHttpTransport. "
10501051
"Prefer close_async() for graceful async shutdown. "
@@ -1067,10 +1068,7 @@ async def close_async(
10671068
semantics as :py:meth:`Client.flush_async`.
10681069
"""
10691070
if self.transport is not None:
1070-
if not (
1071-
ASYNC_TRANSPORT_ENABLED
1072-
and isinstance(self.transport, AsyncHttpTransport)
1073-
):
1071+
if not self._is_async_transport():
10741072
logger.debug(
10751073
"close_async() used with non-async transport, aborting. Please use close() instead."
10761074
)
@@ -1095,9 +1093,7 @@ def flush(
10951093
:param callback: Is invoked with the number of pending events and the configured timeout.
10961094
"""
10971095
if self.transport is not None:
1098-
if ASYNC_TRANSPORT_ENABLED and isinstance(
1099-
self.transport, AsyncHttpTransport
1100-
):
1096+
if self._is_async_transport():
11011097
logger.warning(
11021098
"flush() used with AsyncHttpTransport. Please use flush_async() instead."
11031099
)
@@ -1121,10 +1117,7 @@ async def flush_async(
11211117
:param callback: Is invoked with the number of pending events and the configured timeout.
11221118
"""
11231119
if self.transport is not None:
1124-
if not (
1125-
ASYNC_TRANSPORT_ENABLED
1126-
and isinstance(self.transport, AsyncHttpTransport)
1127-
):
1120+
if not self._is_async_transport():
11281121
logger.debug(
11291122
"flush_async() used with non-async transport, aborting. Please use flush() instead."
11301123
)

sentry_sdk/integrations/asyncio.py

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
reraise,
1212
is_internal_task,
1313
)
14-
from sentry_sdk.transport import ASYNC_TRANSPORT_ENABLED, AsyncHttpTransport
14+
from sentry_sdk.transport import AsyncHttpTransport
1515

1616
try:
1717
import asyncio
@@ -68,10 +68,7 @@ async def _flush() -> None:
6868
return
6969

7070
try:
71-
if not (
72-
ASYNC_TRANSPORT_ENABLED
73-
and isinstance(client.transport, AsyncHttpTransport)
74-
):
71+
if not isinstance(client.transport, AsyncHttpTransport):
7572
return
7673

7774
await client.close_async()

0 commit comments

Comments
 (0)