Example #1
0
    def send_async(
        self,
        receiver_address: Address,
        queue_name: bytes,
        message: Message,
    ):
        if not self._running:
            return
        self.log.info(
            'SEND ASYNC',
            receiver_address=to_normalized_address(receiver_address),
            message=message,
            queue_name=queue_name,
        )
        if not is_binary_address(receiver_address):
            raise ValueError('Invalid address {}'.format(
                pex(receiver_address)))

        # These are not protocol messages, but transport specific messages
        if isinstance(message, (Delivered, Ping, Pong)):
            raise ValueError(
                'Do not use send_async for {} messages'.format(
                    message.__class__.__name__), )

        message_id = message.message_identifier
        async_result = AsyncResult()
        if isinstance(message, Processed):
            async_result.set(
                True)  # processed messages shouldn't get a Delivered reply
            self._send_immediate(receiver_address,
                                 json.dumps(message.to_dict()))
        else:
            self._messageids_to_asyncresult[message_id] = async_result
            self._send_with_retry(receiver_address, async_result,
                                  json.dumps(message.to_dict()))
Example #2
0
    def send_async(
        self,
        receiver_address: Address,
        queue_name: bytes,
        message: Message,
    ):
        if not self._running:
            return
        self.log.info(
            'SEND ASYNC',
            receiver_address=to_normalized_address(receiver_address),
            message=message,
            queue_name=queue_name,
        )
        if not is_binary_address(receiver_address):
            raise ValueError('Invalid address {}'.format(pex(receiver_address)))

        # These are not protocol messages, but transport specific messages
        if isinstance(message, (Delivered, Ping, Pong)):
            raise ValueError(
                'Do not use send_async for {} messages'.format(message.__class__.__name__),
            )

        message_id = message.message_identifier
        async_result = AsyncResult()
        if isinstance(message, Processed):
            async_result.set(True)  # processed messages shouldn't get a Delivered reply
            self._send_immediate(receiver_address, json.dumps(message.to_dict()))
        else:
            self._messageids_to_asyncresult[message_id] = async_result
            self._send_with_retry(receiver_address, async_result, json.dumps(message.to_dict()))
Example #3
0
    def send_async(
        self,
        receiver_address: typing.Address,
        queue_name: bytes,
        message: Message,
    ) -> AsyncResult:
        if not self._running:
            return
        self.log.debug(
            'SEND ASYNC',
            receiver_address=to_normalized_address(receiver_address),
            message=message,
            queue_name=queue_name,
        )
        if not is_binary_address(receiver_address):
            raise ValueError('Invalid address {}'.format(pex(receiver_address)))

        # These are not protocol messages, but transport specific messages
        if isinstance(message, (Delivered, Ping, Pong)):
            raise ValueError(
                'Do not use send_async for {} messages'.format(message.__class__.__name__),
            )

        if isinstance(message, SignedMessage) and not message.sender:
            # FIXME: This can't be right
            message.sender = self._client.user_id

        # Ignore duplicated messages
        message_id = message.message_identifier
        if message_id not in self._messageids_to_asyncresult:
            async_result = self._messageids_to_asyncresult[message_id] = AsyncResult()
            self._send_with_retry(receiver_address, async_result, json.dumps(message.to_dict()))

        return self._messageids_to_asyncresult[message_id]
Example #4
0
    def _send_immediate(
        self,
        queue_identifier: QueueIdentifier,
        message: Message,
    ):
        data = json.dumps(message.to_dict())
        receiver_address = queue_identifier.recipient

        self._send_raw(receiver_address, data)
Example #5
0
    def _send_with_retry(
        self,
        queue_identifier: QueueIdentifier,
        message: Message,
    ):
        data = json.dumps(message.to_dict())
        message_id = message.message_identifier
        receiver_address = queue_identifier.recipient
        reachable = {UserPresence.ONLINE, UserPresence.UNAVAILABLE}

        def retry():
            timeout_generator = udp_utils.timeout_exponential_backoff(
                self._config['retries_before_backoff'],
                self._config['retry_interval'],
                self._config['retry_interval'] * 10,
            )
            for delay in timeout_generator:
                status = self._address_to_presence.get(receiver_address)
                if status in reachable:
                    self._send_raw(receiver_address, data)
                else:
                    self.log.debug(
                        'Skipping SEND to unreachable node',
                        receiver=pex(receiver_address),
                        status=status,
                        message=message,
                        queue=queue_identifier,
                    )
                # equivalent of gevent.sleep, but bails out when stopping
                if self._stop_event.wait(delay):
                    break
                # retry while our queue is valid
                if queue_identifier not in self._queueids_to_queues:
                    self.log.debug(
                        'Queue cleaned, stop retrying',
                        message=message,
                        queue=queue_identifier,
                        queueids_to_queues=self._queueids_to_queues,
                    )
                    break
                # retry while the message is in queue
                # Delivered and Processed messages should eventually remove them
                message_in_queue = any(
                    message_id == event.message_identifier
                    for event in self._queueids_to_queues[queue_identifier]
                )
                if not message_in_queue:
                    break

        self._spawn(retry)