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
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)
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"
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()
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)
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()