从SQS检索多条消息

时间:2012-03-31 21:07:27

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

我在SQS中有多条消息。以下代码始终仅返回一个,即使有几十个可见(不在飞行中)。 setMaxNumberOfMessages我以为会允许多次被消费。我误解了吗?

 CreateQueueRequest createQueueRequest = new CreateQueueRequest().withQueueName(queueName);
 String queueUrl = sqs.createQueue(createQueueRequest).getQueueUrl();
 ReceiveMessageRequest receiveMessageRequest = new ReceiveMessageRequest(queueUrl);
 receiveMessageRequest.setMaxNumberOfMessages(10);
 List<Message> messages = sqs.receiveMessage(receiveMessageRequest).getMessages();
 for (Message message : messages) {
      // i'm a message from SQS
 }

我也试过使用withMaxNumberOfMessages而没有任何运气:

 receiveMessageRequest.withMaxNumberOfMessages(10);

我怎么知道队列中有消息?超过1?

 Set<String> attrs = new HashSet<String>();
 attrs.add("ApproximateNumberOfMessages");
 CreateQueueRequest createQueueRequest = new CreateQueueRequest().withQueueName(queueName);
 GetQueueAttributesRequest a = new GetQueueAttributesRequest().withQueueUrl(sqs.createQueue(createQueueRequest).getQueueUrl()).withAttributeNames(attrs);
 Map<String,String> result = sqs.getQueueAttributes(a).getAttributes();
 int num = Integer.parseInt(result.get("ApproximateNumberOfMessages"));

上述内容始终在之前运行,并且为int提供了> 1

感谢您的输入

8 个答案:

答案 0 :(得分:32)

AWS API Reference Guide: Query/QueryReceiveMessage

  

由于队列的分布式特性,在ReceiveMessage调用上对加权随机机器集进行采样。这意味着只返回采样机器上的消息。如果队列中的消息数量很少(小于1000),则可能会获得比每次ReceiveMessage调用请求的消息少的消息。如果队列中的消息数量非常小,您可能不会在特定的ReceiveMessage响应中收到任何消息;在这种情况下,您应该重复请求。

  

MaxNumberOfMessages :要返回的最大邮件数。 SQS永远不会返回比此值更多的消息,但可能会返回更少的

答案 1 :(得分:8)

SQS reference documentation中的这种(可以说是相当特殊的)行为有一个全面的解释。

SQS stores copies of messages on multiple servers并使用two possible strategies之一

接收对这些服务器的消息请求
  • 短轮询:查询默认行为仅服务器的子集(基于加权随机分布)
  • 长轮询:通过将 WaitTimeSeconds 属性设置为非零值启用,查询所有服务器

在实践中,对于我的有限测试,我似乎总是像你一样得到一条短轮询的消息。

答案 2 :(得分:4)

我遇到了同样的问题。您的队列设置的接收消息等待时间是多少?当我的时间为0时,即使队列中有8个,它也只返回1条消息。当我增加接收消息等待时间时,我得到了所有这些。对我来说似乎有点儿麻烦。

答案 3 :(得分:1)

  

receiveMessageRequest.withMaxNumberOfMessages(10);

为了清楚起见,更实际的用法是添加到你的构造函数中:

ReceiveMessageRequest receiveMessageRequest = new ReceiveMessageRequest(queueUrl).withMaxNumberOfMessages(10);

否则,你可以这样做:

receiveMessageRequest.setMaxNumberOfMessages(10);

话虽如此,改变这一点对原来的问题没有帮助。

答案 4 :(得分:1)

我只是尝试了同样的事情,在这两个属性setMaxNumberOfMessages和setWaitTimeSeconds的帮助下,我能够获得10条消息。

ReceiveMessageRequest receiveMessageRequest = new ReceiveMessageRequest(myQueueUrl);
                      receiveMessageRequest.setMaxNumberOfMessages(10);
                      receiveMessageRequest.setWaitTimeSeconds(20);

o / p的快照:

Receiving messages from TestQueue.
Number of messages:10
Message
MessageId:     31a7c669-1f0c-4bf1-b18b-c7fa31f4e82d 
...

答案 5 :(得分:0)

感谢Caoilte!

我也遇到了这个问题。最后使用长轮询解决,请按照以下配置进行操作: https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-configure-long-polling-for-queue.html

不幸的是,要使用长轮询,您必须将队列创建为FIFO 1。我没有运气就尝试了标准队列。

并且在接收时,还需要设置MaxNumberOfMessages。所以我的代码就像:

ReceiveMessageRequest receive_request =新的ReceiveMessageRequest()                 .withQueueUrl(QUEUE_URL)                 .withWaitTimeSeconds(20)                 .withMaxNumberOfMessages(10);

尽管解决了,但仍然感觉太有线了。 AWS绝对应该为这种基本的接收操作提供更简洁的API。

从我的角度来看,AWS具有许多很酷的功能,但没有好的API。就像那些家伙一直在赶时间。

答案 6 :(得分:0)

这是一种解决方法,您可以异步调用receiveMessageFromSQS方法。

   bulkReceiveFromSQS (queueUrl, totalMessages, asyncLimit, batchSize, visibilityTimeout, waitTime, callback) {
    batchSize = Math.min(batchSize, 10);

    let self = this,
        noOfIterations = Math.ceil(totalMessages / batchSize);

    async.timesLimit(noOfIterations, asyncLimit, function(n, next) {
        self.receiveMessageFromSQS(queueUrl, batchSize, visibilityTimeout, waitTime,
            function(err, result) {
                if (err) {
                    return next(err);
                }

                return next(null, _.get(result, 'Messages'));
            });
    }, function (err, listOfMessages) {
        if (err) {
            return callback(err);
        }
        listOfMessages = _.flatten(listOfMessages).filter(Boolean);

        return callback(null, listOfMessages);
    });
}

它将返回一个具有给定数量消息的数组

答案 7 :(得分:0)

对于小任务列表,我使用stackoverflow.com/a/55149351/13678017之类的FIFO队列 例如修改后的AWS tutorial

            // Create a queue.
        System.out.println("Creating a new Amazon SQS FIFO queue called " + "MyFifoQueue.fifo.\n");
        final Map<String, String> attributes = new HashMap<>();

        // A FIFO queue must have the FifoQueue attribute set to true.
        attributes.put("FifoQueue", "true");
        /*
         * If the user doesn't provide a MessageDeduplicationId, generate a
         * MessageDeduplicationId based on the content.
         */
        attributes.put("ContentBasedDeduplication", "true");
        // The FIFO queue name must end with the .fifo suffix.
        final CreateQueueRequest createQueueRequest = new CreateQueueRequest("MyFifoQueue4.fifo")
                        .withAttributes(attributes);
        final String myQueueUrl = sqs.createQueue(createQueueRequest).getQueueUrl();

        // List all queues.
        System.out.println("Listing all queues in your account.\n");
        for (final String queueUrl : sqs.listQueues().getQueueUrls()) {
            System.out.println("  QueueUrl: " + queueUrl);
        }
        System.out.println();

        // Send a message.
        System.out.println("Sending a message to MyQueue.\n");

        for (int i = 0; i < 4; i++) {

            var request = new SendMessageRequest()
                    .withQueueUrl(myQueueUrl)
                    .withMessageBody("message " + i)
                    .withMessageGroupId("userId1");
                    ;

            sqs.sendMessage(request);
        }

        for (int i = 0; i < 6; i++) {

            var request = new SendMessageRequest()
                    .withQueueUrl(myQueueUrl)
                    .withMessageBody("message " + i)
                    .withMessageGroupId("userId2");
                    ;

            sqs.sendMessage(request);
        }

        // Receive messages.
        System.out.println("Receiving messages from MyQueue.\n");
        var receiveMessageRequest = new ReceiveMessageRequest(myQueueUrl);

        receiveMessageRequest.setMaxNumberOfMessages(10);
        receiveMessageRequest.setWaitTimeSeconds(20);

        // what receive?
        receiveMessageRequest.withMessageAttributeNames("userId2");


        final List<Message> messages = sqs.receiveMessage(receiveMessageRequest).getMessages();
        for (final Message message : messages) {
            System.out.println("Message");
            System.out.println("  MessageId:     "
                    + message.getMessageId());
            System.out.println("  ReceiptHandle: "
                    + message.getReceiptHandle());
            System.out.println("  MD5OfBody:     "
                    + message.getMD5OfBody());
            System.out.println("  Body:          "
                    + message.getBody());
            for (final Entry<String, String> entry : message.getAttributes()
                    .entrySet()) {
                System.out.println("Attribute");
                System.out.println("  Name:  " + entry
                        .getKey());
                System.out.println("  Value: " + entry
                        .getValue());
            }
        }