def _queue_has_viable_messages()

in bedrock/contentful/management/commands/update_contentful.py [0:0]


    def _queue_has_viable_messages(self) -> bool:
        """
        When pages/entries change, Contentful uses a webhook to push a
        message into a queue. Here, we get all enqueued messages and if ANY ONE
        of them has an action of a 'go' type, we count that as enough and
        we re-sync all of our Contentful content.

        If we get a 'go' signal, we explicitly drain the queue rather than waste
        network I/O on pointless checking. If we don't get a 'go' signal at all,
        we still effectively have purged the queue, just iteratively.

        What action types count as a 'go' signal?

        * auto_save -> YES if using preview mode (ie on Dev/Stage)
        * create -> NO, NEVER - not on Prod, Stage or Dev
        * publish -> YES
        * save -> YES if using preview mode
        * unarchive -> YES
        * archive -> YES (and we'll remove the page from bedrock's DB as well)
        * unpublish  -> YES (as above)
        * delete -> YES (as above)
        """

        poll_queue = True
        may_purge_queue = False
        viable_message_found = False

        GO_ACTIONS = {
            ACTION_ARCHIVE,
            ACTION_PUBLISH,
            ACTION_UNARCHIVE,
            ACTION_UNPUBLISH,
            ACTION_DELETE,
        }
        EXTRA_PREVIEW_API_GO_ACTIONS = {
            # Sites that are using the preview API key (Dev and Stage) act upon
            # two more state changes
            ACTION_AUTO_SAVE,
            ACTION_SAVE,
        }

        if settings.APP_NAME != "bedrock-prod":
            # See settings.base.get_app_name()
            GO_ACTIONS = GO_ACTIONS.union(EXTRA_PREVIEW_API_GO_ACTIONS)

        if not settings.CONTENTFUL_NOTIFICATION_QUEUE_ACCESS_KEY_ID:
            self.log(
                "AWS SQS Credentials not configured for Contentful webhook",
            )
            # We don't want things to block/fail if we don't have SQS config.
            # Instead, in this situation, it's better to just assume we got
            # a 'go' signal and poll Contentful anyway.
            return True

        sqs = boto3.resource(
            "sqs",
            region_name=settings.CONTENTFUL_NOTIFICATION_QUEUE_REGION,
            aws_access_key_id=settings.CONTENTFUL_NOTIFICATION_QUEUE_ACCESS_KEY_ID,
            aws_secret_access_key=settings.CONTENTFUL_NOTIFICATION_QUEUE_SECRET_ACCESS_KEY,
        )
        queue = sqs.Queue(settings.CONTENTFUL_NOTIFICATION_QUEUE_URL)

        while poll_queue:
            msg_batch = queue.receive_messages(
                WaitTimeSeconds=settings.CONTENTFUL_NOTIFICATION_QUEUE_WAIT_TIME,
                MaxNumberOfMessages=MAX_MESSAGES_PER_QUEUE_POLL,
            )

            if len(msg_batch) == 0:
                self.log("No messages in the queue")
                break

            for sqs_msg in msg_batch:
                msg_body = sqs_msg.body
                action = self._get_message_action(msg_body)
                if action in GO_ACTIONS:
                    # we've found a viable one, so that's great. Drain down the queue and move on
                    viable_message_found = True
                    self.log(f"Got a viable message: {msg_body}")
                    may_purge_queue = True
                    poll_queue = False  # no need to get more messages
                    break
                else:
                    # Explicitly delete the message and move on to the next one.
                    # Note that we don't purge the entire queue even if all of the
                    # current messages are inviable, because we don't want the risk
                    # of a viable message being lost during the purge process.
                    sqs_msg.delete()
                    continue

        if not viable_message_found:
            self.log("No viable message found in queue")

        if may_purge_queue:
            self._purge_queue(queue)

        return viable_message_found