Skip to content

Commit bdca31d

Browse files
BYKsentrivana
andauthored
breaking(transport): Make HTTP2Transport the default (#4492)
Making the HTTP2 transport the default when `h2` and `httpcore` packages are installed. We've been testing this on Sentry SaaS for a while without any issues. We should promote installing the SDK as `sentry-sdk[http2]` for this to be picked up though. Since we still have to support Python 3.7 and `h2` not being supported there, we cannot install it by default and use HTTP2 directly. --------- Co-authored-by: Ivana Kellyer <[email protected]>
1 parent 38cc2a8 commit bdca31d

File tree

7 files changed

+64
-26
lines changed

7 files changed

+64
-26
lines changed

MIGRATION_GUIDE.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ sentry_sdk.init(
3333

3434
- The SDK now supports Python 3.7 and higher.
3535
- Tag values on event dictionaries, which are passed to `before_send` and `before_send_transaction`, now are always `str` values. Previously, despite tag values being typed as `str`, they often had different values. Therefore, if you have configured any `before_send` and `before_send_transaction` functions which perform some logic based on tag values, you need to check and if needed update those functions to correctly handle `str` values.
36+
- The SDK now uses HTTP/2 for its default transport. This can be disabled via setting `http2=False` in `sentry_sdk.init()`. This change also affects `socket_options` as HTTP/2 requires persistent connections. If you want to disable keep-alive, consider disabling HTTP/2 as passing an empty list to `socket_options` would _not_ disable keep alive.
3637

3738
#### Error Capturing
3839

sentry_sdk/consts.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,6 @@ class CompressionAlgo(Enum):
7777
"transport_compression_level": Optional[int],
7878
"transport_compression_algo": Optional[CompressionAlgo],
7979
"transport_num_pools": Optional[int],
80-
"transport_http2": Optional[bool],
8180
"transport_async": Optional[bool],
8281
},
8382
total=False,
@@ -971,6 +970,7 @@ def __init__(
971970
max_stack_frames: Optional[int] = DEFAULT_MAX_STACK_FRAMES,
972971
enable_logs: bool = False,
973972
before_send_log: Optional[Callable[[Log, Hint], Optional[Log]]] = None,
973+
http2: Optional[bool] = None,
974974
) -> None:
975975
"""Initialize the Sentry SDK with the given parameters. All parameters described here can be used in a call to `sentry_sdk.init()`.
976976
@@ -1343,6 +1343,8 @@ def __init__(
13431343
This is relative to the tracing sample rate - e.g. `0.5` means 50% of sampled transactions will be
13441344
profiled.
13451345
1346+
:param http2: Defaults to `True`, enables HTTP/2 support for the SDK.
1347+
13461348
:param profiles_sampler:
13471349
13481350
:param profiler_mode:

sentry_sdk/transport.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1051,7 +1051,12 @@ def _make_pool(
10511051
def make_transport(options: Dict[str, Any]) -> Optional[Transport]:
10521052
ref_transport = options["transport"]
10531053

1054-
use_http2_transport = options.get("_experiments", {}).get("transport_http2", False)
1054+
# We default to using HTTP2 transport if the user also has the required h2
1055+
# library installed (through the subclass check). The reason is h2 not being
1056+
# available on py3.7 which we still support.
1057+
use_http2_transport = options.get("http2") is not False and not issubclass(
1058+
Http2Transport, HttpTransport
1059+
)
10551060
use_async_transport = options.get("_experiments", {}).get("transport_async", False)
10561061
async_integration = any(
10571062
integration.__class__.__name__ == "AsyncioIntegration"

tests/integrations/excepthook/test_excepthook.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@
55
from textwrap import dedent
66

77

8-
TEST_PARAMETERS = [("", "HttpTransport")]
8+
TEST_PARAMETERS = [("http2=False", "HttpTransport")]
99

1010
if sys.version_info >= (3, 8):
11-
TEST_PARAMETERS.append(('_experiments={"transport_http2": True}', "Http2Transport"))
11+
TEST_PARAMETERS.append(("", "Http2Transport"))
1212

1313

1414
@pytest.mark.parametrize("options, transport", TEST_PARAMETERS)

tests/integrations/typer/test_typer.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ def capture_envelope(self, envelope):
2626
if event is not None:
2727
print(event)
2828
29-
transport.HttpTransport.capture_envelope = capture_envelope
29+
transport.BaseHttpTransport.capture_envelope = capture_envelope
3030
3131
init("http://foobar@localhost/123", integrations=[TyperIntegration()])
3232

tests/test_client.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -257,8 +257,8 @@ def test_proxy(monkeypatch, testcase, http2):
257257

258258
kwargs = {}
259259

260-
if http2:
261-
kwargs["_experiments"] = {"transport_http2": True}
260+
if not http2:
261+
kwargs["http2"] = False
262262

263263
if testcase["arg_http_proxy"] is not None:
264264
kwargs["http_proxy"] = testcase["arg_http_proxy"]

tests/test_transport.py

Lines changed: 49 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ def mock_transaction_envelope(span_count: int) -> Envelope:
8383
@pytest.mark.parametrize("use_pickle", (True, False))
8484
@pytest.mark.parametrize("compression_level", (0, 9, None))
8585
@pytest.mark.parametrize("compression_algo", ("gzip", "br", "<invalid>", None))
86-
@pytest.mark.parametrize("http2", [True, False] if PY38 else [False])
86+
@pytest.mark.parametrize("http2", [None, False])
8787
def test_transport_works(
8888
capturing_server,
8989
request,
@@ -106,11 +106,9 @@ def test_transport_works(
106106
if compression_algo is not None:
107107
experiments["transport_compression_algo"] = compression_algo
108108

109-
if http2:
110-
experiments["transport_http2"] = True
111-
112109
client = make_client(
113110
debug=debug,
111+
http2=http2,
114112
_experiments=experiments,
115113
)
116114

@@ -245,7 +243,7 @@ def test_transport_num_pools(make_client, num_pools, expected_num_pools):
245243
if num_pools is not None:
246244
_experiments["transport_num_pools"] = num_pools
247245

248-
client = make_client(_experiments=_experiments)
246+
client = make_client(_experiments=_experiments, http2=False)
249247

250248
options = client.transport._get_pool_options()
251249
assert options["num_pools"] == expected_num_pools
@@ -255,17 +253,13 @@ def test_transport_num_pools(make_client, num_pools, expected_num_pools):
255253
"http2", [True, False] if sys.version_info >= (3, 8) else [False]
256254
)
257255
def test_two_way_ssl_authentication(make_client, http2):
258-
_experiments = {}
259-
if http2:
260-
_experiments["transport_http2"] = True
261-
262256
current_dir = os.path.dirname(__file__)
263257
cert_file = f"{current_dir}/test.pem"
264258
key_file = f"{current_dir}/test.key"
265259
client = make_client(
266260
cert_file=cert_file,
267261
key_file=key_file,
268-
_experiments=_experiments,
262+
http2=http2,
269263
)
270264
options = client.transport._get_pool_options()
271265

@@ -290,20 +284,20 @@ def test_socket_options(make_client):
290284

291285

292286
def test_keep_alive_true(make_client):
293-
client = make_client(keep_alive=True)
287+
client = make_client(keep_alive=True, http2=False)
294288

295289
options = client.transport._get_pool_options()
296290
assert options["socket_options"] == KEEP_ALIVE_SOCKET_OPTIONS
297291

298292

299293
def test_keep_alive_on_by_default(make_client):
300-
client = make_client()
294+
client = make_client(http2=False)
301295
options = client.transport._get_pool_options()
302296
assert "socket_options" not in options
303297

304298

305299
def test_default_timeout(make_client):
306-
client = make_client()
300+
client = make_client(http2=False)
307301

308302
options = client.transport._get_pool_options()
309303
assert "timeout" in options
@@ -312,7 +306,7 @@ def test_default_timeout(make_client):
312306

313307
@pytest.mark.skipif(not PY38, reason="HTTP2 libraries are only available in py3.8+")
314308
def test_default_timeout_http2(make_client):
315-
client = make_client(_experiments={"transport_http2": True})
309+
client = make_client()
316310

317311
with mock.patch(
318312
"sentry_sdk.transport.httpcore.ConnectionPool.request",
@@ -335,15 +329,15 @@ def test_default_timeout_http2(make_client):
335329

336330
@pytest.mark.skipif(not PY38, reason="HTTP2 libraries are only available in py3.8+")
337331
def test_http2_with_https_dsn(make_client):
338-
client = make_client(_experiments={"transport_http2": True})
332+
client = make_client()
339333
client.transport.parsed_dsn.scheme = "https"
340334
options = client.transport._get_pool_options()
341335
assert options["http2"] is True
342336

343337

344338
@pytest.mark.skipif(not PY38, reason="HTTP2 libraries are only available in py3.8+")
345339
def test_no_http2_with_http_dsn(make_client):
346-
client = make_client(_experiments={"transport_http2": True})
340+
client = make_client()
347341
client.transport.parsed_dsn.scheme = "http"
348342
options = client.transport._get_pool_options()
349343
assert options["http2"] is False
@@ -356,19 +350,44 @@ def test_socket_options_override_keep_alive(make_client):
356350
(socket.SOL_TCP, socket.TCP_KEEPCNT, 6),
357351
]
358352

359-
client = make_client(socket_options=socket_options, keep_alive=False)
353+
client = make_client(socket_options=socket_options, keep_alive=False, http2=False)
360354

361355
options = client.transport._get_pool_options()
362356
assert options["socket_options"] == socket_options
363357

364358

359+
@pytest.mark.skipif(not PY38, reason="HTTP2 libraries are only available in py3.8+")
360+
def test_socket_options_merge_with_keep_alive_http2(make_client):
361+
socket_options = [
362+
(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 42),
363+
(socket.SOL_TCP, socket.TCP_KEEPINTVL, 42),
364+
]
365+
366+
client = make_client(socket_options=socket_options)
367+
368+
options = client.transport._get_pool_options()
369+
try:
370+
assert options["socket_options"] == [
371+
(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 42),
372+
(socket.SOL_TCP, socket.TCP_KEEPINTVL, 42),
373+
(socket.SOL_TCP, socket.TCP_KEEPIDLE, 45),
374+
(socket.SOL_TCP, socket.TCP_KEEPCNT, 6),
375+
]
376+
except AttributeError:
377+
assert options["socket_options"] == [
378+
(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 42),
379+
(socket.SOL_TCP, socket.TCP_KEEPINTVL, 42),
380+
(socket.SOL_TCP, socket.TCP_KEEPCNT, 6),
381+
]
382+
383+
365384
def test_socket_options_merge_with_keep_alive(make_client):
366385
socket_options = [
367386
(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 42),
368387
(socket.SOL_TCP, socket.TCP_KEEPINTVL, 42),
369388
]
370389

371-
client = make_client(socket_options=socket_options, keep_alive=True)
390+
client = make_client(socket_options=socket_options, keep_alive=True, http2=False)
372391

373392
options = client.transport._get_pool_options()
374393
try:
@@ -386,12 +405,23 @@ def test_socket_options_merge_with_keep_alive(make_client):
386405
]
387406

388407

389-
def test_socket_options_override_defaults(make_client):
408+
@pytest.mark.skipif(not PY38, reason="HTTP2 libraries are only available in py3.8+")
409+
def test_socket_options_override_defaults_http2(make_client):
390410
# If socket_options are set to [], this doesn't mean the user doesn't want
391411
# any custom socket_options, but rather that they want to disable the urllib3
392412
# socket option defaults, so we need to set this and not ignore it.
393413
client = make_client(socket_options=[])
394414

415+
options = client.transport._get_pool_options()
416+
assert options["socket_options"] == KEEP_ALIVE_SOCKET_OPTIONS
417+
418+
419+
def test_socket_options_override_defaults(make_client):
420+
# If socket_options are set to [], this doesn't mean the user doesn't want
421+
# any custom socket_options, but rather that they want to disable the urllib3
422+
# socket option defaults, so we need to set this and not ignore it.
423+
client = make_client(http2=False, socket_options=[])
424+
395425
options = client.transport._get_pool_options()
396426
assert options["socket_options"] == []
397427

0 commit comments

Comments
 (0)