Как мне избежать аргумента цикла - PullRequest
0 голосов
/ 18 октября 2019

Следующий код является частью некоторых автоматических тестов, которые я написал на 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)

По сути, вызов start_server должен инициировать простой веб-сервер с конечной точкой sockjs с именем /sockjs

Я пока не владею ключевым словом Python async. Я подозреваю, что есть две проблемы:

Во-первых, я получаю предупреждение об устаревании оператора app = web.Application(loop=loop):

/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)

И, во-вторых, тесты время от времени терпят неудачу. Я считаю, что, в зависимости от загрузки компьютера, иногда серверу не хватало времени для запуска, прежде чем тестовый код действительно начнет выполняться.

В принципе, мне нужно, чтобы функция start_server инициализировала сеть. приложение с конечной точкой веб-сокета и не возвращать до тех пор, пока приложение не будет готово принимать подключения веб-сокета.

Ответы [ 2 ]

0 голосов
/ 20 октября 2019

Пожалуйста, обновите sockjs до последней версии. Больше не требуется проходить цикл .

0 голосов
/ 20 октября 2019

Во-первых, я получаю предупреждение об устаревании в приложении = web.Application(loop=loop) оператор:

Рекомендуемый способ избежать обхода loop везде - это переключиться на asyncio.run. Вместо того, чтобы управлять циклом вручную, позвольте asyncio.run создать (и закрыть) цикл для вас. Если вся ваша работа выполняется в сопрограммах, вы можете получить доступ к циклу с помощью get_event_loop() или get_running_loop().

По сути, мне нужно, чтобы функция start_server инициализировала веб-приложение с помощью веб-сокетаконечной точки, и не возвращать, пока приложение не будет готово принимать соединения через веб-сокет.

Вы можете передать threading.Event потоку, который устанавливается при настройке сайта, и ждать его восновной поток.

Вот (непроверенный) пример, который реализует оба предложения:

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()
...