コード例 #1
0
class ProcessChannelNotificationUseCase(ChannelNotificationUseCase):
    MAX_ATTEMPTS = 3

    def __init__(self, channel_notification_repo: ChannelNotificationRepo,
                 bc_inbox_repo: BCInboxRepo, routing_table):
        super().__init__(channel_notification_repo)
        self.routing_table = routing_table
        self.enqueue_message_use_case = EnqueueMessageUseCase(bc_inbox_repo)

    def execute(self):
        """
        Get message from channel API and post it to message API.
        Retry in case of failure
        """
        job = self.channel_notification_repo.get_job()
        if not job:
            return
        super().execute()
        queue_message_id, job_payload = job
        attempt = job_payload[self.ATTEMPT]

        try:
            self.process(job_payload)
        except ChannelApiFailure as e:
            increase_counter(
                "usecase.ProcessChannelNotificationUseCase.failure")
            logger.info("%s: processing channel notification failure",
                        queue_message_id)
            logger.exception(e)
            if attempt < self.MAX_ATTEMPTS:
                attempt += 1
                EnqueueChannelNotificationUseCase(
                    self.channel_notification_repo).retry(
                        job_payload, attempt)
                self.channel_notification_repo.delete(queue_message_id)
                return
            raise
        else:
            self.channel_notification_repo.delete(queue_message_id)

    def process(self, job_payload):
        logger.debug("Processing job: %r", job_payload)
        channel_id = job_payload[self.CHANNEL_ID]
        channel = get_channel_by_id(channel_id, self.routing_table)
        if not channel:
            raise ChannelNotFound("Channel not found, id: %s" % channel_id)

        notification_payload = job_payload[self.NOTIFICATION_PAYLOAD]
        message = self._get_message(channel, notification_payload['id'])
        self.enqueue_message_use_case.execute(message)
        increase_counter("usecase.ProcessChannelNotificationUseCase.processed")

    def _get_message(self, channel, message_id):
        request_channel_use_case = RequestChannelAPIUseCase(channel)
        message_payload = request_channel_use_case.get_message(message_id)
        message = Message.from_dict(message_payload['message'])
        message.status = "received"
        message.sender_ref = str(uuid.uuid4())
        return message
コード例 #2
0
def test_enque_false_if_message_without_sender_ref(valid_message_dicts):
    inbox = mock.Mock()
    inbox.post.return_value = False
    m_dict = valid_message_dicts[0]
    # m_dict["sender_ref"] = uuid.uuid4()
    # del m_dict["sender_ref"]

    m = protocol.Message.from_dict(m_dict)
    use_case = EnqueueMessageUseCase(inbox)
    with pytest.raises(Exception):
        use_case.execute(m)
コード例 #3
0
def test_enque_false_if_message_invalid_predicate(valid_message_dicts):
    inbox = mock.Mock()
    inbox.post.return_value = False
    m_dict = valid_message_dicts[0]
    m_dict["sender_ref"] = uuid.uuid4()
    m_dict["predicate"] = None  # Oop, invalid
    m = protocol.Message.from_dict(m_dict)
    use_case = EnqueueMessageUseCase(inbox)
    with pytest.raises(Exception) as e:
        use_case.execute(m)
        assert str(e) == "can't enqueue invalid message"
コード例 #4
0
def message_post():
    """
    Puts message to the message lake and into the processing queue
    """
    body = request.get_json(silent=True)
    if not body or not isinstance(body, dict):
        raise MessageDataEmptyError()

    try:
        message = Message.from_dict(body)
    except Exception as e:
        raise MessageDeserializationError(source=[str(e)])
    if not message.is_valid():
        raise MessageValidationError(source=message.validation_errors())

    # we fill it for message_api but not for message_rx_api
    if not message.sender_ref:
        message.kwargs["sender_ref"] = str(uuid.uuid4())

    # because we are first who sees that message
    message.kwargs["status"] = "pending"

    repo = BCInboxRepo(Config.BC_INBOX_CONF)
    use_case = EnqueueMessageUseCase(repo)

    if use_case.execute(message):
        return Response(
            json.dumps(message, cls=ser.MessageJSONEncoder),
            status=HTTPStatus.CREATED,
            mimetype='application/json',
            # headers={'Location': message_url}
        )
    else:
        raise UnableWriteToInboxError()
コード例 #5
0
def test_enque_false_if_inbox_rejects_message(valid_message_dicts):
    inbox = mock.Mock()
    inbox.post.return_value = False
    m_dict = valid_message_dicts[0]
    m_dict["sender_ref"] = uuid.uuid4()
    m = protocol.Message.from_dict(m_dict)
    use_case = EnqueueMessageUseCase(inbox)
    assert not use_case.execute(m)
コード例 #6
0
def message():
    """
    Usage:
        curl -XPOST http://127.0.0.1:5000/messages \
            -H 'Content-type: application/json' \
            -d '{"adf": "ee"}'
    """
    # silent prevents default error which is BadRequest
    body = request.get_json(silent=True)
    if not body or not isinstance(body, dict):
        raise MessageDataEmptyError()

    try:
        message = Message.from_dict(body, require_allowed=["sender_ref"])
    except Exception as e:
        raise MessageDeserializationError(source=[str(e)])
    if not message.is_valid():
        raise MessageValidationError(source=message.validation_errors())

    message_url = message.absolute_object_uri()
    if not message_url:
        raise MessageAbsoluteURLError()

    message.kwargs["status"] = "received"  # because it's RX api

    repo = BCInboxRepo(
        Config.BC_INBOX_CONF
    )

    use_case = EnqueueMessageUseCase(repo)

    if use_case.execute(message):
        return Response(
            json.dumps(message, cls=ser.MessageJSONEncoder),
            status=201,
            mimetype='application/json',
            headers={'Location': message_url}
        )
    else:
        raise UnableWriteToInboxError()