Пример #1
0
class AsyncClient(baseasync.BaseAsync):
    def __init__(self, *args, **kwargs):
        super(AsyncClient, self).__init__(*args, **kwargs)
        self.pool = eventlet.greenpool.GreenPool(DEFAULT_POOL_SIZE)
        self.reader_thread = None
        self.writer_thread = None
        self.queue = Queue(DEFAULT_MAX_QUEUE_SIZE)
        self.max_pending = MAX_PENDING
        self.closing = False

    def build_socket(self, family=socket.AF_INET):
        return socket.socket(family)

    def connect(self):
        super(AsyncClient, self).connect()
        self.closing = False
        self.reader_thread = eventlet.greenthread.spawn(self._reader_run)
        self.writer_thread = eventlet.greenthread.spawn(self._writer_run)

    def dispatch(self, fn, *args, **kwargs):
        if LOG.isEnabledFor(logging.DEBUG):
            LOG.debug("Dispatching: Pending {0}".format(len(self._pending)))
        self.pool.spawn_n(fn, *args, **kwargs)

    def shutdown(self):
        self.closing = True
        if len(self._pending) + self.queue.qsize() == 0:
            self._end_close()

    def close(self):
        self.shutdown()
        self.wait()

    def _end_close(self):
        self.writer_thread.kill()
        self.reader_thread.kill()

        super(AsyncClient, self).close()

        self.writer_thread = None
        self.reader_thread = None

    def sendAsync(self, header, value, onSuccess, onError):
        if self.closing:
            raise common.ConnectionClosed(
                "Client is closing, can't queue more operations.")

        if self.faulted:
            self._raise(
                common.ConnectionFaulted(
                    "Can't send message when connection is on a faulted state."
                ), onError)
            return  #skip the rest

        # fail fast on NotConnected
        if not self.isConnected:
            self._raise(common.NotConnected("Not connected."), onError)
            return  #skip the rest

        if LOG.isEnabledFor(logging.DEBUG):
            LOG.debug("Queue: {0}".format(self.queue.qsize()))
        self.queue.put((header, value, onSuccess, onError))
        eventlet.sleep(0)

    def wait(self):
        self.queue.join()

    def send(self, header, value):
        done = eventlet.event.Event()

        class Dummy:
            pass

        d = Dummy()
        d.error = None
        d.result = None

        def innerSuccess(m, r, value):
            d.result = (m, r, value)
            done.send()

        def innerError(e):
            d.error = e
            done.send()

        self.sendAsync(header, value, innerSuccess, innerError)

        done.wait()  # TODO(Nacho): should be add a default timeout?
        if d.error: raise d.error
        return d.result

    def _writer_run(self):
        while self.isConnected and not self.faulted:
            try:
                while len(self._pending) > self.max_pending:
                    eventlet.sleep(0)
                (header, value, onSuccess, onError) = self.queue.get()
                super(AsyncClient, self).sendAsync(header, value, onSuccess,
                                                   onError)
            except common.ConnectionFaulted:
                pass
            except common.ConnectionClosed:
                pass
            except Exception as ex:
                self._fault_client(ex)

            # Yield execution, don't starve the reader
            eventlet.sleep(0)

    def _reader_run(self):
        while self.isConnected and not self.faulted:
            try:
                self._async_recv()
                self.queue.task_done()
                if self.closing and len(
                        self._pending) + self.queue.qsize() == 0:
                    self._end_close()
            except common.ConnectionFaulted:
                pass
            except Exception as ex:
                self._fault_client(ex)
Пример #2
0
class Client(baseasync.BaseAsync):
    def __init__(self, *args, **kwargs):
        super(Client, self).__init__(*args, **kwargs)
        self.pool = eventlet.greenpool.GreenPool(DEFAULT_POOL_SIZE)
        self.reader_thread = None
        self.writer_thread = None
        self.queue = Queue(DEFAULT_MAX_QUEUE_SIZE)
        self.max_pending = MAX_PENDING
        self.closing = False

    def build_socket(self, family=socket.AF_INET):
        return socket.socket(family)

    def wrap_secure_socket(self, s, ssl_version):
        return GreenSSLSocket(s, ssl_version=ssl_version)

    def connect(self):
        super(Client, self).connect()
        self.closing = False
        self.reader_thread = eventlet.greenthread.spawn(self._reader_run)
        self.writer_thread = eventlet.greenthread.spawn(self._writer_run)

    def dispatch(self, fn, *args, **kwargs):
        if LOG.isEnabledFor(logging.DEBUG):
            LOG.debug("Dispatching: Pending {0}".format(len(self._pending)))
        self.pool.spawn_n(fn, *args, **kwargs)

    def shutdown(self):
        self.closing = True
        if len(self._pending) + self.queue.qsize() == 0:
            self._end_close()

    def close(self):
        self.shutdown()
        self.wait()

    def _end_close(self):
        self.writer_thread.kill()
        self.reader_thread.kill()

        super(Client, self).close()

        self.writer_thread = None
        self.reader_thread = None

    def sendAsync(self, header, value, onSuccess, onError, no_ack=False):
        if self.closing:
            raise common.ConnectionClosed("Client is closing, can't queue more operations.")

        if self.faulted:
            self._raise(common.ConnectionFaulted("Can't send message when connection is on a faulted state."), onError)
            return  # skip the rest

        # fail fast on NotConnected
        if not self.isConnected:
            self._raise(common.NotConnected("Not connected."), onError)
            return  # skip the rest

        if LOG.isEnabledFor(logging.DEBUG):
            LOG.debug("Queue: {0}".format(self.queue.qsize()))
        self.queue.put((header, value, onSuccess, onError, no_ack))
        eventlet.sleep(0)

    def wait(self):
        self.queue.join()

    def send(self, header, value):
        done = eventlet.event.Event()

        class Dummy:
            pass

        d = Dummy()
        d.error = None
        d.result = None

        def innerSuccess(m, r, value):
            d.result = (m, r, value)
            done.send()

        def innerError(e):
            d.error = e
            done.send()

        self.sendAsync(header, value, innerSuccess, innerError)

        done.wait()  # TODO(Nacho): should be add a default timeout?
        if d.error:
            raise d.error
        return d.result

    def _writer_run(self):
        while self.isConnected and not self.faulted:
            try:
                while len(self._pending) > self.max_pending:
                    eventlet.sleep(0)
                (header, value, onSuccess, onError, no_ack) = self.queue.get()
                super(Client, self).sendAsync(header, value, onSuccess, onError, no_ack)
            except common.ConnectionFaulted:
                pass
            except common.ConnectionClosed:
                pass
            except Exception as ex:
                self._fault_client(ex)

            # Yield execution, don't starve the reader
            eventlet.sleep(0)

    def _reader_run(self):
        while self.isConnected and not self.faulted:
            try:
                self._async_recv()
                self.queue.task_done()
                if self.closing and len(self._pending) + self.queue.qsize() == 0:
                    self._end_close()
            except common.ConnectionFaulted:
                pass
            except Exception as ex:
                self._fault_client(ex)