Клиент async websocket на Python с асинхронным таймером

Мне нужен долго работающий клиент websocket, который получает push-сообщения от сервера websocket, и мне нужно отслеживать состояние соединения клиента: если соединение прерывается, мне нужно это выяснить.

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

Моя идея: 1) иметь клиент websocket, который отвечает на нерегулярно входящие сообщения. И 2) в то же время есть цикл, который прекращает регистрацию сообщения, когда клиент websocket выдает исключение ConnectionClosed.

Меня заинтриговал новый синтаксис async 3.5. Эта реализация веб-сокета специально основана на asyncio. client в документации выглядит именно так, как мне нужно.

Однако я понятия не имею, как добавить вторую сопрограмму, которая выполняет мои операторы ведения журнала и каким-то образом останавливается, когда соединение с веб-сокетом вызывает ConnectionClosed.

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

#!/usr/bin/env python

import asyncio
import logging

import websockets

logger = logging.getLogger(__name__)

is_alive = True


async def alive():
    while is_alive:
        logger.info('alive')
        await asyncio.sleep(300)


async def async_processing():
    async with websockets.connect('ws://localhost:8765') as websocket:
        while True:
            try:
                message = await websocket.recv()
                print(message)

            except websockets.exceptions.ConnectionClosed:
                print('ConnectionClosed')
                is_alive = False
                break


asyncio.get_event_loop().run_until_complete(alive())
asyncio.get_event_loop().run_until_complete(async_processing())

person Dan Schien    schedule 20.02.2016    source источник


Ответы (1)


Фактически run_until_complete здесь блокируется, так как ожидает завершения alive.

Вы можете решить эту проблему за 2 шага:

  1. запланировать сопрограммы с помощью asyncio.ensure_future (немедленно запускается, не дожидаясь результатов ), каждое возвращаемое задание.
  2. дождитесь завершения задач с помощью asyncio.wait

Код вроде:

tasks = [
   asyncio.ensure_future(alive()),
   asyncio.ensure_future(async_processing())
]
asyncio.get_event_loop().run_until_complete(asyncio.wait(tasks))

Как упомянул @Vincent, wait принимает задачи, поэтому ensure_future не нужно:

asyncio.get_event_loop().run_until_complete(asyncio.wait([   
   alive(),
   async_processing()
]))
person kwarunek    schedule 20.02.2016
comment
Работает как шарм. Большое спасибо. - person Dan Schien; 21.02.2016
comment
Вы можете передать список сопрограмм в asyncio.wait, не нужно использовать asyncio.ensure_future в вашем примере. - person Vincent; 21.02.2016