Skip to content

Commit 018d2e5

Browse files
committed
Explain application-level keepalives.
Fix #1514.
1 parent 3b2c522 commit 018d2e5

File tree

1 file changed

+40
-0
lines changed

1 file changed

+40
-0
lines changed

docs/topics/keepalive.rst

+40
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,46 @@ application layer.
9090
Read this `blog post <https://making.close.com/posts/reliable-websockets/>`_ for
9191
a complete walk-through of this issue.
9292

93+
Application-level keepalive
94+
---------------------------
95+
96+
Some servers require clients to send a keepalive message with a specific content
97+
at regular intervals. Usually they expect Text_ frames rather than Ping_ frames,
98+
meaning that you must send them with :attr:`~asyncio.connection.Connection.send`
99+
rather than :attr:`~asyncio.connection.Connection.ping`.
100+
101+
.. _Text: https://www.rfc-editor.org/rfc/rfc6455.html#section-5.6
102+
103+
In websockets, such keepalive mechanisms are considered as application-level
104+
because they rely on data frames. That's unlike the protocol-level keepalive
105+
based on control frames. Therefore, it's your responsibility to implement the
106+
required behavior.
107+
108+
You can run a task in the background to send keepalive messages:
109+
110+
.. code-block:: python
111+
112+
import itertools
113+
import json
114+
115+
from websockets import ConnectionClosed
116+
117+
async def keepalive(websocket, ping_interval=30):
118+
for ping in itertools.count():
119+
await asyncio.sleep(ping_interval)
120+
try:
121+
await websocket.send(json.dumps({"ping": ping}))
122+
except ConnectionClosed:
123+
break
124+
125+
async def main():
126+
async with connect(...) as websocket:
127+
keepalive_task = asyncio.create_task(keepalive(websocket))
128+
try:
129+
... # your application logic goes here
130+
finally:
131+
keepalive_task.cancel()
132+
93133
Latency issues
94134
--------------
95135

0 commit comments

Comments
 (0)