简体   繁体   中英

Autobahn Asyncio ReconnectingClientFactory

I would like to make a ReconnectingClientFactory with asyncio. In particular to handle the case that the server is not available when the client is started in which case the ReconnectingClientFactory will keep trying. That is something that the asyncio.events.create_connection does not do.

Concretely:

The EchoClient example would be fine. The crux is how the connection is made.

factory = EchoClientFactory('ws://127.0.0.1:5678')
connectWS(factory)

in the case of the twisted version with ReconnectingClientFactory .

Vs

factory = EchoClientFactory(u"ws://127.0.0.1:5678")
factory.protocol = SecureServerClientProtocol

loop = asyncio.get_event_loop()

# coro = loop.create_connection(factory, 'ws_server', 5678)
coro = loop.create_connection(factory, '127.0.0.1', 5678)

loop.run_until_complete(asyncio.wait([
    alive(), coro
]))
loop.run_forever()
loop.close()

Or similar with the asycnio version.

The problem is that in the asyncio version the connection is established by asyncio.events.create_connection which simply fails if the server is not available.

How can I reconcile the two?

Many thanks

I think I get what you want. Here's the code and example based on asyncio TCP echo client protocol example .

import asyncio
import random


class ReconnectingTCPClientProtocol(asyncio.Protocol):
    max_delay = 3600
    initial_delay = 1.0
    factor = 2.7182818284590451
    jitter = 0.119626565582
    max_retries = None

    def __init__(self, *args, loop=None, **kwargs):
        if loop is None:
            loop = asyncio.get_event_loop()
        self._loop = loop
        self._args = args
        self._kwargs = kwargs
        self._retries = 0
        self._delay = self.initial_delay
        self._continue_trying = True
        self._call_handle = None
        self._connector = None

    def connection_lost(self, exc):
        if self._continue_trying:
            self.retry()

    def connection_failed(self, exc):
        if self._continue_trying:
            self.retry()

    def retry(self):
        if not self._continue_trying:
            return

        self._retries += 1
        if self.max_retries is not None and (self._retries > self.max_retries):
            return

        self._delay = min(self._delay * self.factor, self.max_delay)
        if self.jitter:
            self._delay = random.normalvariate(self._delay,
                                               self._delay * self.jitter)
        self._call_handle = self._loop.call_later(self._delay, self.connect)

    def connect(self):
        if self._connector is None:
            self._connector = self._loop.create_task(self._connect())

    async def _connect(self):
        try:
            await self._loop.create_connection(lambda: self,
                                               *self._args, **self._kwargs)
        except Exception as exc:
            self._loop.call_soon(self.connection_failed, exc)
        finally:
            self._connector = None

    def stop_trying(self):
        if self._call_handle:
            self._call_handle.cancel()
            self._call_handle = None
        self._continue_trying = False
        if self._connector is not None:
            self._connector.cancel()
            self._connector = None


if __name__ == '__main__':
    class EchoClientProtocol(ReconnectingTCPClientProtocol):
        def __init__(self, message, *args, **kwargs):
            super().__init__(*args, **kwargs)
            self.message = message

        def connection_made(self, transport):
            transport.write(self.message.encode())
            print('Data sent: {!r}'.format(self.message))

        def data_received(self, data):
            print('Data received: {!r}'.format(data.decode()))

        def connection_lost(self, exc):
            print('The server closed the connection')
            print('Stop the event loop')
            self._loop.stop()


    loop = asyncio.get_event_loop()
    client = EchoClientProtocol('Hello, world!', '127.0.0.1', 8888, loop=loop)
    client.connect()
    loop.run_forever()
    loop.close()

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM