Skip to content

websocket: Async version of WebSocketHandler.close is needed #2914

Open
@benediamond

Description

@benediamond

NOTE: this is different from #2763. possibly related to #2448, but also distinct.

After starting a websocket server, I am getting

ERROR:asyncio:Task was destroyed but it is pending!
task: <Task pending name='Task-5' coro=<RequestHandler._execute() running at /usr/local/lib/python3.8/site-packages/tornado/web.py:1703> wait_for=<Future pending cb=[<TaskWakeupMethWrapper object at 0x10acb2970>()]> cb=[_HandlerDelegate.execute.<locals>.<lambda>() at /usr/local/lib/python3.8/site-packages/tornado/web.py:2333]>

even after appropriately closing all connections. this is different from #2763, where the unresolved task was WebSocketProtocol13._receive_frame_loop, and not all connections were closed.

to reproduce this easily, run the following tiny python3 program:

import asyncio
from abc import ABC
import tornado.websocket
import tornado.httpserver
import tornado.ioloop
import tornado.web

handlers = []
class Handler(tornado.websocket.WebSocketHandler, ABC):
    def open(self):  # making this async and awaiting write_message doesn't silence the tornado warnings.
        handlers.append(self)
    def on_message(self, message):
        pass
    def on_close(self):
        pass
    def check_origin(self, origin):
        return True
application = tornado.web.Application([
    (r'/', Handler),
])
http_server = tornado.httpserver.HTTPServer(application)
loop = tornado.ioloop.IOLoop.current()
async def my_function():  # closes the connections, stops the server, stops the loop after 20s.
    await asyncio.sleep(20.0)
    for handler in handlers:
        handler.close()
    http_server.stop()
    loop.stop()
http_server.listen(8080)
loop.add_callback(my_function)
loop.start()
loop.close()

in a separate Node.js console (for example), run:

const WebSocket = require('ws');
new WebSocket('ws://localhost:8080')

the culprit appears to be the future fut here, which is never awaited:

tornado/tornado/web.py

Lines 2323 to 2326 in 79b9c4f

fut = gen.convert_yielded(
self.handler._execute(transforms, *self.path_args, **self.path_kwargs)
)
fut.add_done_callback(lambda f: f.result())

tornado version: tornado-6.0.4. Python version: 3.8.5.

i am unable to further diagnose the issue, or fix it. thanks for your attention and time.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions