模式以持续监听AWS SQS消息

时间:2017-12-20 18:01:04

标签: java amazon-web-services sdk amazon-sqs

我有一个名为QueueService的简单类,其中包含一些从AWS SQS SDK for Java中包装方法的方法。例如:

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;
    }

我还有另一个名为App的类,其main并创建了QueueService的实例。

我正在寻找一个“模式”来使main中的App侦听队列中的新消息。现在我有一个while(true)循环,我调用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);
            }
        }

这是正确的方法吗?我应该在SQS SDK中使用异步消息接收方法吗?

3 个答案:

答案 0 :(得分:8)

据我所知,亚马逊SQS无法支持亚马逊SQS推送的活跃侦听器模型。消息发送给您的侦听器,或者在有消息时调用消息侦听器。

因此,您总是需要轮询消息。轮询支持两种轮询机制 - 短轮询和长轮询。每个都有自己的优点和缺点,但长轮询是大多数情况下通常最终会使用的,但默认的是短轮询。长轮询机制在网络流量方面肯定更有效,更具成本效益(因为亚马逊根据请求的数量向您收费),并且当您希望以时间敏感的方式处理消息时,它也是首选机制( 〜=尽快处理。)

有很多关于长轮询和短轮询的错综复杂的内容值得了解,而且这里的所有内容都有些难以解释,但如果您愿意,可以通过以下博客阅读更多有关此内容的详细信息。它也有一些代码示例,应该会有所帮助。

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

就一段时间(真实)循环而言,我认为这取决于。 如果您正在使用长轮询,并且您可以将等待时间设置为(最多)20秒,那么如果没有消息,则不会超过20秒轮询SQS。如果有消息,您可以决定是否经常轮询(一旦消息到达就处理消息),或者是否总是以时间间隔(比如每n秒)处理消息。

需要注意的另一点是,您可以在单个receiveMessages请求中读取最多10条消息,这样也会减少您对SQS进行的呼叫次数,从而降低成本。正如上面的博客详细解释的那样,您可以请求阅读10条消息,但即使队列中有很多消息,它也可能不会返回10。

一般情况下,我会说你需要构建适当的钩子和异常处理,以便在运行时关闭轮询,以防你使用while(true)类型的结构。

要考虑的另一个方面是您是想在主应用程序线程中轮询SQS还是想要生成另一个线程。所以另一种选择可能是创建一个ScheduledThreadPoolExecutor,在main中有一个单独的线程来安排一个线程定期轮询SQS(每隔几秒),你可能不需要while(true)结构。

答案 1 :(得分:2)

您遗失了一些事情:

  • 使用rtb.InsertImage(image); 并设置等待时间以启用长轮询。
  • 将您的AWS调用包装在try / catch块中。特别要注意receiveMessages(ReceiveMessageRequest),如果您有太多的机上留言,可以从OverLimitException投出。
  • receiveMessages()循环的整个主体包装在自己的try / catch块中,记录捕获的任何异常(不应该 - 这是为了确保您的应用程序不会崩溃,因为AWS更改了他们的API,或者您忽略了处理预期的异常。)

有关长轮询和可能的例外情况的详细信息,请参阅doc

至于使用异步客户端:你有什么特别的理由使用它吗?如果没有,则不要:单个接收器线程更容易管理。

答案 2 :(得分:0)

如果您想使用SQS然后使用lambda来处理请求,您可以按照link中给出的步骤进行操作,或者始终使用lambda而不是SQS并为每个请求调用lambda。