Skip to content

Commit 30847a0

Browse files
Max concurrent stream improvements (#90)
1 parent 717da48 commit 30847a0

File tree

2 files changed

+66
-66
lines changed

2 files changed

+66
-66
lines changed

httpcore/_async/http2.py

Lines changed: 33 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ def max_streams_semaphore(self) -> AsyncSemaphore:
7272
# We do this lazily, to make sure backend autodetection always
7373
# runs within an async context.
7474
if not hasattr(self, "_max_streams_semaphore"):
75-
max_streams = self.h2_state.remote_settings.max_concurrent_streams
75+
max_streams = self.h2_state.local_settings.max_concurrent_streams
7676
self._max_streams_semaphore = self.backend.create_semaphore(
7777
max_streams, exc_class=PoolTimeout
7878
)
@@ -102,6 +102,8 @@ async def request(
102102
await self.send_connection_init(timeout)
103103
self.sent_connection_init = True
104104

105+
await self.max_streams_semaphore.acquire()
106+
try:
105107
try:
106108
stream_id = self.h2_state.get_next_available_stream_id()
107109
except NoAvailableStreamIDError:
@@ -110,10 +112,13 @@ async def request(
110112
else:
111113
self.state = ConnectionState.ACTIVE
112114

113-
h2_stream = AsyncHTTP2Stream(stream_id=stream_id, connection=self)
114-
self.streams[stream_id] = h2_stream
115-
self.events[stream_id] = []
116-
return await h2_stream.request(method, url, headers, stream, timeout)
115+
h2_stream = AsyncHTTP2Stream(stream_id=stream_id, connection=self)
116+
self.streams[stream_id] = h2_stream
117+
self.events[stream_id] = []
118+
return await h2_stream.request(method, url, headers, stream, timeout)
119+
except Exception:
120+
self.max_streams_semaphore.release()
121+
raise
117122

118123
async def send_connection_init(self, timeout: TimeoutDict) -> None:
119124
"""
@@ -242,15 +247,18 @@ async def acknowledge_received_data(
242247
await self.socket.write(data_to_send, timeout)
243248

244249
async def close_stream(self, stream_id: int) -> None:
245-
logger.trace("close_stream stream_id=%r", stream_id)
246-
del self.streams[stream_id]
247-
del self.events[stream_id]
248-
249-
if not self.streams:
250-
if self.state == ConnectionState.ACTIVE:
251-
self.state = ConnectionState.IDLE
252-
elif self.state == ConnectionState.FULL:
253-
await self.aclose()
250+
try:
251+
logger.trace("close_stream stream_id=%r", stream_id)
252+
del self.streams[stream_id]
253+
del self.events[stream_id]
254+
255+
if not self.streams:
256+
if self.state == ConnectionState.ACTIVE:
257+
self.state = ConnectionState.IDLE
258+
elif self.state == ConnectionState.FULL:
259+
await self.aclose()
260+
finally:
261+
self.max_streams_semaphore.release()
254262

255263

256264
class AsyncHTTP2Stream:
@@ -276,21 +284,16 @@ async def request(
276284
b"content-length" in seen_headers or b"transfer-encoding" in seen_headers
277285
)
278286

279-
await self.connection.max_streams_semaphore.acquire()
280-
try:
281-
await self.send_headers(method, url, headers, has_body, timeout)
282-
if has_body:
283-
await self.send_body(stream, timeout)
284-
285-
# Receive the response.
286-
status_code, headers = await self.receive_response(timeout)
287-
reason_phrase = get_reason_phrase(status_code)
288-
stream = AsyncByteStream(
289-
aiterator=self.body_iter(timeout), aclose_func=self._response_closed
290-
)
291-
except Exception:
292-
self.connection.max_streams_semaphore.release()
293-
raise
287+
await self.send_headers(method, url, headers, has_body, timeout)
288+
if has_body:
289+
await self.send_body(stream, timeout)
290+
291+
# Receive the response.
292+
status_code, headers = await self.receive_response(timeout)
293+
reason_phrase = get_reason_phrase(status_code)
294+
stream = AsyncByteStream(
295+
aiterator=self.body_iter(timeout), aclose_func=self._response_closed
296+
)
294297

295298
return (b"HTTP/2", status_code, reason_phrase, headers, stream)
296299

@@ -362,7 +365,4 @@ async def body_iter(self, timeout: TimeoutDict) -> AsyncIterator[bytes]:
362365
break
363366

364367
async def _response_closed(self) -> None:
365-
try:
366-
await self.connection.close_stream(self.stream_id)
367-
finally:
368-
self.connection.max_streams_semaphore.release()
368+
await self.connection.close_stream(self.stream_id)

httpcore/_sync/http2.py

Lines changed: 33 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ def max_streams_semaphore(self) -> SyncSemaphore:
7272
# We do this lazily, to make sure backend autodetection always
7373
# runs within an async context.
7474
if not hasattr(self, "_max_streams_semaphore"):
75-
max_streams = self.h2_state.remote_settings.max_concurrent_streams
75+
max_streams = self.h2_state.local_settings.max_concurrent_streams
7676
self._max_streams_semaphore = self.backend.create_semaphore(
7777
max_streams, exc_class=PoolTimeout
7878
)
@@ -102,6 +102,8 @@ def request(
102102
self.send_connection_init(timeout)
103103
self.sent_connection_init = True
104104

105+
self.max_streams_semaphore.acquire()
106+
try:
105107
try:
106108
stream_id = self.h2_state.get_next_available_stream_id()
107109
except NoAvailableStreamIDError:
@@ -110,10 +112,13 @@ def request(
110112
else:
111113
self.state = ConnectionState.ACTIVE
112114

113-
h2_stream = SyncHTTP2Stream(stream_id=stream_id, connection=self)
114-
self.streams[stream_id] = h2_stream
115-
self.events[stream_id] = []
116-
return h2_stream.request(method, url, headers, stream, timeout)
115+
h2_stream = SyncHTTP2Stream(stream_id=stream_id, connection=self)
116+
self.streams[stream_id] = h2_stream
117+
self.events[stream_id] = []
118+
return h2_stream.request(method, url, headers, stream, timeout)
119+
except Exception:
120+
self.max_streams_semaphore.release()
121+
raise
117122

118123
def send_connection_init(self, timeout: TimeoutDict) -> None:
119124
"""
@@ -242,15 +247,18 @@ def acknowledge_received_data(
242247
self.socket.write(data_to_send, timeout)
243248

244249
def close_stream(self, stream_id: int) -> None:
245-
logger.trace("close_stream stream_id=%r", stream_id)
246-
del self.streams[stream_id]
247-
del self.events[stream_id]
248-
249-
if not self.streams:
250-
if self.state == ConnectionState.ACTIVE:
251-
self.state = ConnectionState.IDLE
252-
elif self.state == ConnectionState.FULL:
253-
self.close()
250+
try:
251+
logger.trace("close_stream stream_id=%r", stream_id)
252+
del self.streams[stream_id]
253+
del self.events[stream_id]
254+
255+
if not self.streams:
256+
if self.state == ConnectionState.ACTIVE:
257+
self.state = ConnectionState.IDLE
258+
elif self.state == ConnectionState.FULL:
259+
self.close()
260+
finally:
261+
self.max_streams_semaphore.release()
254262

255263

256264
class SyncHTTP2Stream:
@@ -276,21 +284,16 @@ def request(
276284
b"content-length" in seen_headers or b"transfer-encoding" in seen_headers
277285
)
278286

279-
self.connection.max_streams_semaphore.acquire()
280-
try:
281-
self.send_headers(method, url, headers, has_body, timeout)
282-
if has_body:
283-
self.send_body(stream, timeout)
284-
285-
# Receive the response.
286-
status_code, headers = self.receive_response(timeout)
287-
reason_phrase = get_reason_phrase(status_code)
288-
stream = SyncByteStream(
289-
iterator=self.body_iter(timeout), close_func=self._response_closed
290-
)
291-
except Exception:
292-
self.connection.max_streams_semaphore.release()
293-
raise
287+
self.send_headers(method, url, headers, has_body, timeout)
288+
if has_body:
289+
self.send_body(stream, timeout)
290+
291+
# Receive the response.
292+
status_code, headers = self.receive_response(timeout)
293+
reason_phrase = get_reason_phrase(status_code)
294+
stream = SyncByteStream(
295+
iterator=self.body_iter(timeout), close_func=self._response_closed
296+
)
294297

295298
return (b"HTTP/2", status_code, reason_phrase, headers, stream)
296299

@@ -362,7 +365,4 @@ def body_iter(self, timeout: TimeoutDict) -> Iterator[bytes]:
362365
break
363366

364367
def _response_closed(self) -> None:
365-
try:
366-
self.connection.close_stream(self.stream_id)
367-
finally:
368-
self.connection.max_streams_semaphore.release()
368+
self.connection.close_stream(self.stream_id)

0 commit comments

Comments
 (0)