How do I avoid the loop argument

妖精的绣舞 提交于 2020-01-16 14:34:10

问题


The following code is part of some automated tests that I have written in python 3.6:

connected = False

def aiohttp_server(loop):
    async def handler(msg, session):
        global connected
        if msg.type == sockjs.MSG_OPEN:
            connected = True
        if msg.type == sockjs.MSG_CLOSE:
            connected = False

    app = web.Application(loop=loop)
    sockjs.add_endpoint(app, handler)
    runner = web.AppRunner(app)
    return runner

def run_server(runner, loop):
    logging.basicConfig(level=logging.DEBUG,
                        format='%(asctime)s %(levelname)s %(message)s')

    asyncio.set_event_loop(loop)
    loop.run_until_complete(runner.setup())
    site = web.TCPSite(runner, 'localhost', 8080)
    loop.run_until_complete(site.start())
    loop.run_forever()

def start_server():
    loop = asyncio.new_event_loop()
    t = threading.Thread(target=run_server, args=(aiohttp_server(loop),loop,), daemon=True)
    t.start()
    time.sleep(0.01)

Basically, calling start_server should initiate a simple web server with a sockjs endpoint named /sockjs

I am not yet a master of python's async keyword. There are two issues, that I suspect are related:

Firstly, I am getting a deprecation warning on the app = web.Application(loop=loop) statement:

/home/peter/incubator/sockjs_client/tests/test_sockjs_client.py:25: DeprecationWarning: loop argument is deprecated
  app = web.Application(loop=loop)
/home/peter/.local/lib/python3.6/site-packages/sockjs/route.py:54: DeprecationWarning: loop property is deprecated
  manager = SessionManager(name, app, handler, app.loop)

And secondly, the tests fail occasionally. I believe that, depending on machine load, sometimes the server hasn't had enough time to start before the test code actually starts executing.

Basically, what I need is for the start_server function to initialise a web application with a websocket endpoint, and not return until the application is prepared to accept websocket connections.


回答1:


Firstly, I am getting a deprecation warning on the app = web.Application(loop=loop) statement:

The recommended way to avoid passing around the loop everywhere is to switch to asyncio.run. Instead of managing the loop manually, let asyncio.run create (and close) the loop for you. If all your work is done in coroutines, you can access the loop with get_event_loop() or get_running_loop().

Basically, what I need is for the start_server function to initialise a web application with a websocket endpoint, and not return until the application is prepared to accept websocket connections.

You can pass a threading.Event to the thread that gets set when the site is set up, and wait for it in the main thread.

Here is an (untested) example that implements both suggestions:

connected = False

def aiohttp_server():
    async def handler(msg, session):
        global connected
        if msg.type == sockjs.MSG_OPEN:
            connected = True
        if msg.type == sockjs.MSG_CLOSE:
            connected = False

    app = web.Application()
    sockjs.add_endpoint(app, handler)
    return web.AppRunner(app)

async def run_server(ready):
    logging.basicConfig(level=logging.DEBUG,
                        format='%(asctime)s %(levelname)s %(message)s')
    runner = aiohttp_server()
    await runner.setup()
    site = web.TCPSite(runner, 'localhost', 8080)
    await site.start()
    ready.set()
    # emulates loop.run_forever()
    await asyncio.get_running_loop().create_future()

def start_server():
    ready = threading.Event()
    threading.Thread(target=asyncio.run, args=(aiohttp_server(ready),),
                     daemon=True).start()
    ready.wait()



回答2:


Please upgrade sockjs to the newest version. It doesn't require passing the loop anymore.



来源:https://stackoverflow.com/questions/58455058/how-do-i-avoid-the-loop-argument

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!