Skip to content

Commit 4592d03

Browse files
authored
Add support for adjusting the server WebSocket writer limit (#9572) (#9573)
1 parent 78418f7 commit 4592d03

File tree

4 files changed

+28
-2
lines changed

4 files changed

+28
-2
lines changed

CHANGES/9572.feature.rst

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Added ``writer_limit`` to the :py:class:`~aiohttp.web.WebSocketResponse` to be able to adjust the limit before the writer forces the buffer to be drained -- by :user:`bdraco`.

aiohttp/web_ws.py

+8-1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
from multidict import CIMultiDict
1111

1212
from . import hdrs
13+
from ._websocket.writer import DEFAULT_LIMIT
1314
from .abc import AbstractStreamWriter
1415
from .helpers import calculate_timeout_when, set_exception, set_result
1516
from .http import (
@@ -70,6 +71,7 @@ def __init__(
7071
protocols: Iterable[str] = (),
7172
compress: bool = True,
7273
max_msg_size: int = 4 * 1024 * 1024,
74+
writer_limit: int = DEFAULT_LIMIT,
7375
) -> None:
7476
super().__init__(status=101)
7577
self._protocols = protocols
@@ -97,6 +99,7 @@ def __init__(
9799
self._compress = compress
98100
self._max_msg_size = max_msg_size
99101
self._ping_task: Optional[asyncio.Task[None]] = None
102+
self._writer_limit = writer_limit
100103

101104
def _cancel_heartbeat(self) -> None:
102105
self._cancel_pong_response_cb()
@@ -305,7 +308,11 @@ def _pre_start(self, request: BaseRequest) -> Tuple[str, WebSocketWriter]:
305308
transport = request._protocol.transport
306309
assert transport is not None
307310
writer = WebSocketWriter(
308-
request._protocol, transport, compress=compress, notakeover=notakeover
311+
request._protocol,
312+
transport,
313+
compress=compress,
314+
notakeover=notakeover,
315+
limit=self._writer_limit,
309316
)
310317

311318
return protocol, writer

docs/web_reference.rst

+7-1
Original file line numberDiff line numberDiff line change
@@ -954,7 +954,8 @@ and :ref:`aiohttp-web-signals` handlers::
954954

955955
.. class:: WebSocketResponse(*, timeout=10.0, receive_timeout=None, \
956956
autoclose=True, autoping=True, heartbeat=None, \
957-
protocols=(), compress=True, max_msg_size=4194304)
957+
protocols=(), compress=True, max_msg_size=4194304, \
958+
writer_limit=65536)
958959

959960
Class for handling server-side websockets, inherited from
960961
:class:`StreamResponse`.
@@ -1005,6 +1006,11 @@ and :ref:`aiohttp-web-signals` handlers::
10051006
``request.transport.close()`` to avoid
10061007
leaking resources.
10071008

1009+
:param int writer_limit: maximum size of write buffer, 64 KB by default.
1010+
Once the buffer is full, the websocket will pause
1011+
to drain the buffer.
1012+
1013+
.. versionadded:: 3.11
10081014

10091015
The class supports ``async for`` statement for iterating over
10101016
incoming messages::

tests/test_web_websocket.py

+12
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,18 @@ def test_closed_after_ctor() -> None:
249249
assert ws.close_code is None
250250

251251

252+
async def test_raise_writer_limit(make_request) -> None:
253+
"""Test the writer limit can be adjusted."""
254+
req = make_request("GET", "/")
255+
ws = WebSocketResponse(writer_limit=1234567)
256+
await ws.prepare(req)
257+
assert ws._reader is not None
258+
assert ws._writer is not None
259+
assert ws._writer._limit == 1234567
260+
ws._reader.feed_data(WS_CLOSED_MESSAGE)
261+
await ws.close()
262+
263+
252264
async def test_send_str_closed(make_request) -> None:
253265
req = make_request("GET", "/")
254266
ws = WebSocketResponse()

0 commit comments

Comments
 (0)