Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/amazon-web-services/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 模式以持续侦听AWS SQS消息_Java_Amazon Web Services_Sdk_Amazon Sqs - Fatal编程技术网

Java 模式以持续侦听AWS SQS消息

Java 模式以持续侦听AWS SQS消息,java,amazon-web-services,sdk,amazon-sqs,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(

我有一个名为
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;
    }

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

您缺少一些东西:

  • 使用
    receiveMessages(ReceiveMessageRequest)
    并设置等待时间以启用长轮询
  • 将AWS调用包装在try/catch块中。特别要注意
    OverLimitException
    ,如果飞行中的消息太多,则可能会从
    receiveMessages()
    引发该异常
  • while
    循环的整个主体包装在它自己的try/catch块中,记录捕获到的任何异常(不应该有——这是为了确保应用程序不会因为AWS更改了API或您忽略了处理预期异常而崩溃)
有关长轮询和可能的异常的更多信息,请参阅


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

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

据我所知,Amazon SQS无法支持主动侦听器模型,其中Amazon SQS将“推送”消息到您的侦听器,或者在有消息时调用您的消息侦听器

因此,您必须始终轮询消息。轮询支持两种轮询机制:短轮询和长轮询。每种方法都有各自的优点和缺点,但是在大多数情况下,长轮询是您通常使用的方法,尽管默认的方法是短轮询。就网络流量而言,长轮询机制肯定更有效,更具成本效益(因为Amazon根据请求数量向您收费),而且当您希望以时间敏感的方式处理消息时(尽快处理),长轮询机制也是首选机制

关于长轮询和短轮询,有更多的复杂之处值得了解,在这里解释这些有点困难,但是如果你愿意,你可以通过下面的博客阅读更多的细节。它还有一些代码示例,应该会有所帮助

就while(true)循环而言,我认为这要视情况而定。 如果您使用长轮询,并且可以将等待时间设置为(最多)20秒,那么如果没有消息,您轮询SQS的频率不会超过20秒。如果有消息,您可以决定是频繁轮询(在消息到达时立即处理消息)还是始终按时间间隔处理消息(例如每n秒)

另一点需要注意的是,您可以在一个receiveMessages请求中读取多达10条消息,因此这也将减少您向SQS拨打的电话数量,从而降低成本。正如上面的博客详细解释的那样,您可能会请求阅读10条消息,但即使队列中有那么多消息,它也可能不会返回10条消息

不过,一般来说,如果您希望在运行时关闭轮询,我会说您需要构建适当的钩子和异常处理,以防使用while(true)类型的结构


另一个要考虑的问题是,您是否希望在主应用程序线程中查询SQL,或者希望生成另一个线程。因此,另一种选择可能是创建一个ScheduledThreadPoolExecutor,主线程为一个线程,以安排一个线程定期(每隔几秒钟)轮询SQS,并且您可能不需要while(true)结构。

使用异步客户机的原因是,将来会有一个应用程序(.jar)AWS Lambda中托管的服务将使用SQS服务包装器检查队列中是否有新消息要处理。由于Lambda通过事件触发或函数调用来收费,因此我认为只有在有新消息时才执行的侦听器(使用sqs+jws)会更便宜。如果我在最后一点上错了,请您纠正我好吗?异步客户端唯一要做的就是将每个非异步请求包装在一个
可调用的
中,然后在一个内部线程池上运行它。我不确定“SQS服务包装器”是什么,但SQS目前不是受支持的事件源。大多数人使用SNS,有些人使用Kinesis。使用“SQS服务包装器”,我指的是我创建的类,它包装了SQS SDK的一些方法。我找到了一种设置侦听器lo的方法,该侦听器lo在队列中有新消息时触发。我应该更深入地研究文档。谢谢。我读过这篇文章,它使用了一个带有Cloudwatch的时间表,触发一个Lambda函数轮询队列。我试图避免时间调度器。今年SQS可以触发Lambda这在2017年是真的,尽管2018年6月28日,从SQS触发Lambda成为可能:@pzrq还值得注意的是,如果您使用SQS FIFO队列,您无法从SQS触发Lambda。自2019年11月起,还支持从SQS FIFO触发Lambda,但不保证只交付一次
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);
            }
        }