web-dev-qa-db-fra.com

Modèle d'écoute continue des messages AWS SQS

J'ai une classe simple nommée QueueService avec des méthodes qui encapsulent les méthodes du kit AWS SQS SDK for Java. Par exemple:

public ArrayList<Hashtable<String, String>> receiveMessages(String queueURL) {
        List<Message> messages = this.sqsClient.receiveMessage(queueURL).getMessages();

        ArrayList<Hashtable<String, String>> resultList = new ArrayList<Hashtable<String, String>>();
        for(Message message : messages) {
            Hashtable<String, String> resultItem = new Hashtable<String, String>();
            resultItem.put("MessageId", message.getMessageId());
            resultItem.put("ReceiptHandle", message.getReceiptHandle());
            resultItem.put("Body", message.getBody());
            resultList.add(resultItem);
        }
        return resultList;
    }

J'ai une autre classe nommée App qui a une main et crée une instance de QueueService

Je cherche un "modèle" pour que le main dans App soit à l'écoute des nouveaux messages dans la file d'attente. À l’heure actuelle, j’ai une boucle while(true) où j’appelle la méthode receiveMessages:

while(true) {
            messages = queueService.receiveMessages(queueURL); 
            for(Hashtable<String, String> message: messages) {
                String receiptHandle = message.get("ReceiptHandle");
                String messageBody = message.get("MessageBody");
                System.out.println(messageBody);
                queueService.deleteMessage(queueURL, receiptHandle);
            }
        }

Est-ce la bonne façon? Dois-je utiliser la méthode de réception de message asynchrone dans le SDK SQS?

5
Francisco Hanna

À ma connaissance, il n'existe aucun moyen dans Amazon SQS de prendre en charge un modèle d'écouteur actif dans lequel Amazon SQS "transmettrait" les messages à votre écouteur, ou invoquerait votre écouteur de messages lorsqu'il y a des messages.

Ainsi, vous devrez toujours rechercher des messages. Deux mécanismes d'interrogation sont pris en charge pour l'interrogation: l'interrogation courte et l'interrogation longue. Chacune a ses avantages et ses inconvénients, mais l'interrogation longue est celle que vous utiliserez généralement dans la plupart des cas, bien que celle par défaut soit l'interrogation courte. Le mécanisme d'interrogation long est nettement plus efficace en termes de trafic réseau, est plus rentable (car Amazon facture en fonction du nombre de demandes effectuées), et constitue également le mécanisme privilégié lorsque vous souhaitez que vos messages soient traités dans le respect du temps ( ~ = traiter le plus tôt possible).

Il est utile de connaître plus de subtilités autour des sondages longs et des scrutins courts, et il est assez difficile de paraphraser tout cela ici, mais si vous le souhaitez, vous pouvez lire beaucoup plus de détails à ce sujet sur le blog suivant. Il contient également quelques exemples de code qui devraient être utiles.

http://pragmaticnotes.com/2017/11/20/Amazon-sqs-long-polling-versus-short-polling/

En termes de boucle while (true), je dirais que cela dépend. Si vous utilisez l'interrogation longue et que vous pouvez définir le temps d'attente sur 20 secondes au maximum, vous n'interrogerez pas le SQS plus souvent que 20 secondes s'il n'y a pas de message. S'il y a des messages, vous pouvez décider d'interroger fréquemment (de traiter les messages dès leur arrivée) ou de les traiter toujours dans des intervalles de temps (par exemple toutes les n secondes).

Un autre point à noter est que vous pouvez lire jusqu'à 10 messages dans une seule demande receiveMessages, ce qui réduirait également le nombre d'appels que vous effectuez vers SQS, réduisant ainsi les coûts. Et comme l'explique en détail le blog ci-dessus, vous pouvez demander à lire 10 messages, mais il risque de ne pas vous en renvoyer 10, même s'il y a autant de messages dans la file d'attente. 

En règle générale, cependant, je dirais que vous devez créer des hooks et une gestion des exceptions appropriés pour désactiver la scrutation si vous souhaitez le faire au moment de l'exécution, au cas où vous utiliseriez une sorte de structure while (true).

Un autre aspect à considérer est de savoir si vous souhaitez interroger SQS dans votre thread d'application principal ou si vous souhaitez générer un autre thread. Donc, une autre option pourrait être de créer un ScheduledThreadPoolExecutor avec un seul thread dans le fichier principal afin de planifier un thread pour interroger le SQS périodiquement (toutes les quelques secondes) et vous n'aurez peut-être pas besoin d'une structure while (true).

7
Amitkumar Gupta

Il vous manque quelques choses:

  • Utilisez receiveMessages(ReceiveMessageRequest) et définissez un délai d’attente pour permettre une interrogation longue.
  • Enveloppez vos appels AWS dans des blocs try/catch. Faites particulièrement attention à OverLimitException, qui peut être renvoyé de receiveMessages() si vous avez trop de messages en vol.
  • Enveloppez le corps entier de la boucle while dans son propre bloc try/catch, en enregistrant toutes les exceptions interceptées (cela ne devrait pas être le cas. Ceci est ici pour vous assurer que votre application ne plante pas car AWS a modifié son API ou vous avez négligé gérer une exception attendue).

Voir doc pour plus d’informations sur les interrogations longues et les exceptions possibles.

En ce qui concerne l’utilisation du client async: avez-vous une raison particulière de l’utiliser? Sinon, ne le faites pas: un seul thread récepteur est beaucoup plus facile à gérer.

2
guest

Si vous souhaitez utiliser SQS puis lambda pour traiter la demande, vous pouvez suivre les étapes décrites dans le lien - ou vous utilisez toujours lambda au lieu de SQS et appelez lambda pour chaque demande. 

0
jpdave