我有一个名为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中使用异步消息接收方法吗?
答案 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);
并设置等待时间以启用长轮询。receiveMessages(ReceiveMessageRequest)
,如果您有太多的机上留言,可以从OverLimitException
投出。receiveMessages()
循环的整个主体包装在自己的try / catch块中,记录捕获的任何异常(不应该 - 这是为了确保您的应用程序不会崩溃,因为AWS更改了他们的API,或者您忽略了处理预期的异常。)有关长轮询和可能的例外情况的详细信息,请参阅doc。
至于使用异步客户端:你有什么特别的理由使用它吗?如果没有,则不要:单个接收器线程更容易管理。
答案 2 :(得分:0)
如果您想使用SQS然后使用lambda来处理请求,您可以按照link中给出的步骤进行操作,或者始终使用lambda而不是SQS并为每个请求调用lambda。