Example #1
0
    def _submit_message(self, event, queue, msg_id, message, channel="*"):
        """ Create and fire an ActionMessage """
        try:
            message_id = "ID:resilient-54199-{val}-6:2:12:1:1".format(
                val=msg_id)
            reply_to = "/queue/acks.{org}.{queue}".format(org=self.org_id,
                                                          queue=queue)
            destination = "/queue/actions.{org}.{queue}".format(
                org=self.org_id, queue=queue)
            headers = {
                "reply-to": reply_to,
                "expires": "0",
                "timestamp": str(int(time.time()) * 1000),
                "destination": destination,
                "correlation-id": "invid:390",
                "persistent": "True",
                "priority": "4",
                "Co3MessagePayload": "ActionDataDTO",
                "Co3ContentType": "application/json",
                "message-id": message_id,
                "Co3ContextToken": "dummy",
                "subscription": "stomp-{queue}".format(queue=queue)
            }
            try:
                sock = self.actions_sent.get(msg_id)
                if not isinstance(message, dict):
                    message = json.loads(message)
                    assert (isinstance(message, dict))
            except Exception as e:
                LOG.exception("Bad Message<action %d>: %s", msg_id, message)
                if sock:
                    msg = "Bad Message<action %d>! %s" % (msg_id, str(e))
                    self.fire_message(sock, msg)
                return

            if message.get("function"):
                channel = "functions." + message["function"]["name"]
                action_event = FunctionMessage(source=self.parent,
                                               headers=headers,
                                               message=message,
                                               test=True,
                                               test_msg_id=msg_id)
            else:
                channel = "actions." + queue
                action_event = ActionMessage(source=self.parent,
                                             headers=headers,
                                             message=message,
                                             test=True,
                                             test_msg_id=msg_id)
            action_event.parent = event
            self.fire(action_event, channel)
            if sock:
                self.fire_message(sock, "Action Submitted<action %d>" % msg_id)
        except Exception as e:
            LOG.exception("Action Failed<action %d>", msg_id)
            if sock:
                msg = "Action Failed<action %d>: %s" % (msg_id, str(e))
                self.fire_message(sock, msg)
    def on_stomp_message(self, event, headers, message):
        """STOMP produced a message."""
        # Find the queue name from the subscription id (stomp_listener_xxx)
        msg_id = event.frame.headers.get("message-id")
        if not msg_id:
            LOG.error("Received message with no message id. %s",
                      event.frame.info())
            raise ValueError("Stomp message with no message id received")
        elif msg_id in self._resilient_ack_delivery_failures or msg_id in self._stomp_ack_delivery_failures:
            # This is a message we have already processed but we failed to acknowledge
            # Don't process it again, just acknowledge it
            LOG.info(
                "Skipping reprocess of message %s.  Sending saved ack now.",
                msg_id)
            failure_info = self._resilient_ack_delivery_failures.get(msg_id)
            if failure_info:
                self.fire(
                    Send(headers={'correlation-id': headers['correlation-id']},
                         body=failure_info["result"]["body"],
                         destination=headers['reply-to'],
                         message_id=msg_id))
                self._resilient_ack_delivery_failures.pop(msg_id)
            failure_info = self._stomp_ack_delivery_failures.get(msg_id)
            if failure_info:
                self.fire(Ack(event.frame))
                self._stomp_ack_delivery_failures.pop(msg_id)

        else:
            subscription = self.stomp_component.get_subscription(event.frame)
            LOG.debug('STOMP listener: message for %s', subscription)
            queue_name = subscription.split(".", 2)[2]
            channel = "actions." + queue_name

            LOG.debug("Got Message: %s", event.frame.info())

            try:
                # Expect the message payload to always be UTF8 JSON.
                # However, it may contain surrogate pairs, and in Python 3 that causes problems:
                # - surrogate pairs are not allowed by the default (strict) utf8 decoder,
                # - if we pass them, it will cause downstream issues, so we should re-encode.
                try:
                    mstr = message.decode('utf-8')
                except UnicodeDecodeError:
                    LOG.debug("Failed utf8 decode, trying surrogate")
                    mstr = message.decode('utf-8', "surrogatepass").encode(
                        "utf-16", "surrogatepass").decode("utf-16")

                message = json.loads(mstr)
                # Construct a Circuits event with the message, and fire it on the channel
                if message.get("function"):
                    channel = "functions." + message["function"]["name"]
                    event = FunctionMessage(source=self,
                                            headers=headers,
                                            message=message,
                                            frame=event.frame,
                                            log_dir=self.logging_directory)
                else:
                    event = ActionMessage(source=self,
                                          headers=headers,
                                          message=message,
                                          frame=event.frame,
                                          log_dir=self.logging_directory)
                LOG.info("Event: %s Channel: %s", event, channel)

                self.fire(event, channel)
            except Exception as exc:
                LOG.exception(exc)
                if not isinstance(message, dict):
                    LOG.error("DATA:%s", base64.b64encode(message))
                # Normally the event won't be ack'd.  Just report it and carry on.
                if self.ignore_message_failure:
                    # Construct and fire anyway, which will ack the message
                    LOG.warning("This message failure will be ignored...")
                    event = ActionMessage(source=self,
                                          headers=headers,
                                          message=None,
                                          frame=event.frame,
                                          log_dir=self.logging_directory)
                    self.fire(event, channel)