Exemplo n.º 1
0
def test_event_must_be_set():
    queue = NotifyingQueue()
    event_stop = Event()

    data_or_stop = event_first_of(queue, event_stop)

    spawn_after_seconds = 1
    element = 1
    gevent.spawn_later(spawn_after_seconds, add_element_to_queue, queue,
                       element)
    assert data_or_stop.wait()
Exemplo n.º 2
0
def test_event_must_be_set():
    queue = NotifyingQueue()
    event_stop = Event()

    data_or_stop = event_first_of(
        queue,
        event_stop,
    )

    spawn_after_seconds = 1
    element = 1
    gevent.spawn_later(spawn_after_seconds, add_element_to_queue, queue, element)
    assert data_or_stop.wait()
Exemplo n.º 3
0
def single_queue_send(
        transport: 'UDPTransport',
        recipient: typing.Address,
        queue: Queue_T,
        event_stop: Event,
        event_healthy: Event,
        event_unhealthy: Event,
        message_retries: int,
        message_retry_timeout: int,
        message_retry_max_timeout: int,
):
    """ Handles a single message queue for `recipient`.

    Notes:
    - This task must be the only consumer of queue.
    - This task can be killed at any time, but the intended usage is to stop it
      with the event_stop.
    - If there are many queues for the same recipient, it is the
      caller's responsibility to not start them together to avoid congestion.
    - This task assumes the endpoint is never cleared after it's first known.
      If this assumption changes the code must be updated to handle unknown
      addresses.
    """

    # A NotifyingQueue is required to implement cancelability, otherwise the
    # task cannot be stopped while the greenlet waits for an element to be
    # inserted in the queue.
    if not isinstance(queue, NotifyingQueue):
        raise ValueError('queue must be a NotifyingQueue.')

    # Reusing the event, clear must be carefully done
    data_or_stop = event_first_of(
        queue,
        event_stop,
    )

    # Wait for the endpoint registration or to quit
    event_first_of(
        event_healthy,
        event_stop,
    ).wait()

    while True:
        data_or_stop.wait()

        if event_stop.is_set():
            return

        # The queue is not empty at this point, so this won't raise Empty.
        # This task being the only consumer is a requirement.
        (messagedata, message_id) = queue.peek(block=False)

        backoff = timeout_exponential_backoff(
            message_retries,
            message_retry_timeout,
            message_retry_max_timeout,
        )

        try:
            acknowledged = retry_with_recovery(
                transport,
                messagedata,
                message_id,
                recipient,
                event_stop,
                event_healthy,
                event_unhealthy,
                backoff,
            )
        except RaidenShuttingDown:  # For a clean shutdown process
            return

        if acknowledged:
            queue.get()

            # Checking the length of the queue does not trigger a
            # context-switch, so it's safe to assume the length of the queue
            # won't change under our feet and when a new item will be added the
            # event will be set again.
            if not queue:
                data_or_stop.clear()

                if event_stop.is_set():
                    return
Exemplo n.º 4
0
def single_queue_send(
    transport: 'UDPTransport',
    recipient: typing.Address,
    queue: Queue_T,
    queue_identifier: QueueIdentifier,
    event_stop: Event,
    event_healthy: Event,
    event_unhealthy: Event,
    message_retries: int,
    message_retry_timeout: int,
    message_retry_max_timeout: int,
):
    """ Handles a single message queue for `recipient`.

    Notes:
    - This task must be the only consumer of queue.
    - This task can be killed at any time, but the intended usage is to stop it
      with the event_stop.
    - If there are many queues for the same recipient, it is the
      caller's responsibility to not start them together to avoid congestion.
    - This task assumes the endpoint is never cleared after it's first known.
      If this assumption changes the code must be updated to handle unknown
      addresses.
    """

    # A NotifyingQueue is required to implement cancelability, otherwise the
    # task cannot be stopped while the greenlet waits for an element to be
    # inserted in the queue.
    if not isinstance(queue, NotifyingQueue):
        raise ValueError('queue must be a NotifyingQueue.')

    # Reusing the event, clear must be carefully done
    data_or_stop = event_first_of(
        queue,
        event_stop,
    )

    # Wait for the endpoint registration or to quit
    log.debug(
        'queue: waiting for node to become healthy',
        node=pex(transport.raiden.address),
        queue_identifier=queue_identifier,
        queue_size=len(queue),
    )

    event_first_of(
        event_healthy,
        event_stop,
    ).wait()

    log.debug(
        'queue: processing queue',
        node=pex(transport.raiden.address),
        queue_identifier=queue_identifier,
        queue_size=len(queue),
    )

    while True:
        data_or_stop.wait()

        if event_stop.is_set():
            log.debug(
                'queue: stopping',
                node=pex(transport.raiden.address),
                queue_identifier=queue_identifier,
                queue_size=len(queue),
            )
            return

        # The queue is not empty at this point, so this won't raise Empty.
        # This task being the only consumer is a requirement.
        (messagedata, message_id) = queue.peek(block=False)

        log.debug(
            'queue: sending message',
            node=pex(transport.raiden.address),
            recipient=pex(recipient),
            msgid=message_id,
            queue_identifier=queue_identifier,
            queue_size=len(queue),
        )

        backoff = timeout_exponential_backoff(
            message_retries,
            message_retry_timeout,
            message_retry_max_timeout,
        )

        acknowledged = retry_with_recovery(
            transport,
            messagedata,
            message_id,
            recipient,
            event_stop,
            event_healthy,
            event_unhealthy,
            backoff,
        )

        if acknowledged:
            queue.get()

            # Checking the length of the queue does not trigger a
            # context-switch, so it's safe to assume the length of the queue
            # won't change under our feet and when a new item will be added the
            # event will be set again.
            if not queue:
                data_or_stop.clear()

                if event_stop.is_set():
                    return