trio-websocket icon indicating copy to clipboard operation
trio-websocket copied to clipboard

WebSocketServer.run() docs and shutdown

Open pikeas opened this issue 4 years ago • 3 comments

It will block until the server is accepting connections and then return a :class:WebSocketServer object

:returns: This method never returns unless cancelled.

These cannot both be true. The second remark matches the implementation, but the first remark is preferred. Currently, there doesn't seem to be a good way to cleanly shut down the server.

pikeas avatar Jun 05 '21 21:06 pikeas

Ah, it looks like the server is returned via task.status.started(self). Perhaps the docs could be revised:

"When called by nursery.start(serve_websocket, ...) instead of nursery.start_soon, the running instance of WebSocketServer is returned."

pikeas avatar Jun 05 '21 21:06 pikeas

With server = nursery.start(serve_websocket, ...), I believe my original comment still applies - there's no aclose() or sync close() on WebSocketServer for cleanly shutting down the server.

pikeas avatar Jun 05 '21 21:06 pikeas

(I changed the title to WebSocketServer.run() but I see it also applies to serve_websocket().)

Here are the current docs with more context:

This method supports the Trio nursery start protocol: server = await nursery.start(server.run, …). It will block until the server is accepting connections and then return a :class:WebSocketServer object.

It does say that return of the WebSocketServer is done by way of start(), but could it be more clear? The reader is expected to be familiar with the Trio API and start_soon() vs. start().

Note that Trio library functions like serve_listeners() have the same API.

there's no aclose() or sync close() on WebSocketServer for cleanly shutting down the server

Trio has cancel scopes, and API implementations are able to encapsulate both synchronous and asynchronous shutdown. So the way you'd shut down the websocket server is to cancel the parent task. Note that there are two potential cancel points:

async with trio.open_nursery() as nursery:
    # cancel if it takes more than 1 second to start accepting connections
    with trio.fail_after(1):
        await nursery.start(partial(serve_websocket, ...))
    # sorry, this server will self-destruct after 5 minutes
    await trio.sleep(5 * 60)
    nursery.cancel_scope.cancel()

Everything should be cleanly shut down under such cancellations (as well as by Ctrl-C and SIGTERM)-- is there evidence otherwise?

belm0 avatar Jun 05 '21 23:06 belm0