-
-
Notifications
You must be signed in to change notification settings - Fork 543
Common Client Connection Keep-alive Pattern #581
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
Not sure if this helps, but I also struggled with using a bare import EventLoop
class AsyncWSClient:
def __init__(self, url):
self.con = None
self.url = url
self.loop = EventLoop.get_loop()
asyncio.ensure_future(self.connection_object(), loop=self.loop)
asyncio.ensure_future(self.handle_message(), loop=self.loop)
async def connection_object(self):
self.con = await websockets.connect(self.url)
async def handle_message(self):
while not self.con:
await asyncio.sleep(1)
try:
while True:
message = await self.con.recv() I use this client in an event loop that is thrown to a background thread (I throw a bunch of other coroutines back there too, so the main thread is unblocked... nice for testing): class EventLoop:
def start(cls):
cls.loop = asyncio.new_event_loop()
threading.Thread(target=cls._loop_thread_main, name="EventLoopThread", daemon=True)
def get_loop(cls):
if not cls.loop:
cls.start()
return cls.loop()
def cls._loop_thread_main(cls):
try:
cls.loop.run_forever()
except:
pass #usually KBinterrupt
finally:
cls.stop_loop_clean()
def cls.stop_loop_clean(cls):
tasks = asyncio.Task.all_tasks(loop=cls.loop)
cls.loop.call_soon_threadsafe(cls.loop.create_task, cls._clean_tasks(tasks))
cls.thread.join()
cls.loop.stop()
async def _clean_tasks(cls, tasks):
remainder = []
for task in tasks:
cls._logger.info("Cancelling task %s" % task)
task.cancel()
remainder.append(task)
await asyncio.gather(*remainder, return_exceptions=True)
cls.loop.stop() As long as my main thread invokes and starts the EventLoop correctly (this happens in another part of the program), the client connection gets instantiated and services messages until the main program is finished or closed with Ctrl+C. |
Thanks! I will try this and get back to this thread. If I understand it correctly I can also add appropriate documentation |
I don't understand this. while True:
await ... definitely yields to the event loop. Can you clarify what code sample you're referring to? |
I read this issue again today and I haven't been able to nail down what it's about. The ability to keep a connection alive is built-in (and enabled by default [and slightly buggy]) in websockets 7.0. There's documentation about how to shutdown a server properly here: https://websockets.readthedocs.io/en/stable/deployment.html#graceful-shutdown |
#534 might be related too. |
Hi, fantastic library! Using Python 3.7.2 and looking ahead to support 3.8 for the community as well.
Problem
The suggested code,
while True
to keep the websocket client open does not yield back to the main async loop. I believe there are a few folks struggling with that. https://websockets.readthedocs.io/en/stable/intro.html#basic-exampleAdditional issue threads (mostly closed, in order of relevance)
#83, #398, #527, #565, #534, #559
Solutions (6 of them)
stop()
to ceasewhile True
method as in the documentation; can usewebsockets.serve
; this obviously has its weaknessesunsubscribe
property isTrue
Important notes
• 3.7 recommends using
asyncio.run()
as the primary entrance for the loop, and only calling it once• using
async with
as the context manager forces a connection close as exiting the block; is there an elegant way to keep it open outside the block? I don't believe so...but I am not sure•
async for
is no longer suggestedSince this issue seems to be popping up repeatedly, I'm happy to contribute to the documentation if we can find an acceptable solution. Thanks for your help in advance!
The text was updated successfully, but these errors were encountered: