Пример #1
0
async def test_threaded_async_run():
    """Test threaded async runner."""
    runner = ThreadedAsyncRunner()
    runner.start()

    async def fn():
        return "ok"

    assert runner.call(fn()).result() == "ok"
    runner.stop()
Пример #2
0
async def test_threaded_async_run_cancel_task():
    """Test threaded async runner tasks cancelled."""
    runner = ThreadedAsyncRunner()
    runner.start()

    async def fn():
        await asyncio.sleep(1)

    task = runner.call(fn())
    await asyncio.sleep(0.1)
    task.cancel()
    await asyncio.sleep(0.1)
    with pytest.raises(CancelledError):
        task.result()

    assert task.done()

    # cancel before start
    task = runner.call(fn())
    task.cancel()
    with pytest.raises(CancelledError):
        task.result()
    assert task.done()
Пример #3
0
class Multiplexer(AsyncMultiplexer):
    """Transit sync multiplexer for compatibility."""
    def __init__(self, *args, **kwargs):
        """
        Initialize the connection multiplexer.

        :param connections: a sequence of connections.
        :param default_connection_index: the index of the connection to use as default.
                                       | this information is used for envelopes which
                                       | don't specify any routing context.
        :param loop: the event loop to run the multiplexer. If None, a new event loop is created.
        """
        super().__init__(*args, **kwargs)
        self._sync_lock = threading.Lock()
        self._thread_was_started = False
        self._is_connected = False

    def set_loop(self, loop: AbstractEventLoop) -> None:
        """
        Set event loop and all event loopp related objects.

        :param loop: asyncio event loop.
        :return: None
        """
        super().set_loop(loop)
        self._thread_runner = ThreadedAsyncRunner(self._loop)

    def connect(self) -> None:  # type: ignore # cause overrides coroutine # pylint: disable=invalid-overridden-method
        """
        Connect the multiplexer.

        Synchronously in thread spawned if new loop created.
        """
        with self._sync_lock:
            if not self._loop.is_running():
                self._thread_runner.start()
                self._thread_was_started = True

            self._thread_runner.call(super().connect()).result(240)
            self._is_connected = True

    def disconnect(self) -> None:  # type: ignore # cause overrides coroutine # pylint: disable=invalid-overridden-method
        """
        Disconnect the multiplexer.

        Also stops a dedicated thread for event loop if spawned on connect.
        """
        self.logger.debug("Disconnect called")
        with self._sync_lock:
            if not self._loop.is_running():
                return

            if self._is_connected:
                self._thread_runner.call(super().disconnect()).result(240)
                self._is_connected = False
            self.logger.debug("Disconnect async method executed")

            if self._thread_runner.is_alive() and self._thread_was_started:
                self._thread_runner.stop()
                self.logger.debug("Thread stopped")
            self.logger.debug("Disconnected")

    def put(
        self, envelope: Envelope
    ) -> None:  # type: ignore  # cause overrides coroutine
        """
        Schedule an envelope for sending it.

        Notice that the output queue is an asyncio.Queue which uses an event loop
        running on a different thread than the one used in this function.

        :param envelope: the envelope to be sent.
        :return: None
        """
        self._thread_runner.call(super()._put(envelope))  # .result(240)