简体   繁体   English

从 SQS 检索多条消息

[英]Retrieve multiple messages from SQS

I have multiple messages in SQS.我在 SQS 中有多个消息。 The following code always returns only one, even if there are dozens visible (not in flight).下面的代码总是只返回一个,即使有几十个可见(不在飞行中)。 setMaxNumberOfMessages I thought would allow multiple to be consumed at once .. have i misunderstood this? 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
 }

I've also tried using withMaxNumberOfMessages without any such luck:我也试过使用withMaxNumberOfMessages没有任何这样的运气:

 receiveMessageRequest.withMaxNumberOfMessages(10);

How do I know there are messages in the queue?我怎么知道队列中有消息? More than 1?超过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"));

The above always is run prior and gives me an int that is >1以上总是先运行并给我一个> 1的int

Thanks for your input感谢您的输入

AWS API Reference Guide: Query/QueryReceiveMessage AWS API 参考指南:Query/QueryReceiveMessage

Due to the distributed nature of the queue, a weighted random set of machines is sampled on a ReceiveMessage call.由于队列的分布式特性,在 ReceiveMessage 调用中对一组加权的随机机器进行采样。 That means only the messages on the sampled machines are returned.这意味着只返回采样机器上的消息。 If the number of messages in the queue is small (less than 1000), it is likely you will get fewer messages than you requested per ReceiveMessage call.如果队列中的消息数量很少(小于 1000),则您收到的消息可能会少于每次 ReceiveMessage 调用所请求的数量。 If the number of messages in the queue is extremely small, you might not receive any messages in a particular ReceiveMessage response;如果队列中的消息数量极少,您可能不会在特定的 ReceiveMessage 响应中收到任何消息; in which case you should repeat the request.在这种情况下,您应该重复请求。

and

MaxNumberOfMessages : Maximum number of messages to return. MaxNumberOfMessages :要返回的最大消息数。 SQS never returns more messages than this value but might return fewer . SQS 永远不会返回比此值更多的消息,但可能返回更少的

There is a comprehensive explanation for this (arguably rather idiosyncratic) behaviour in the SQS reference documentation . SQS 参考文档中对这种(可以说是相当特殊的)行为进行了全面的解释。

SQS stores copies of messages on multiple servers and receive message requests are made to these servers with one of two possible strategies , SQS 将消息副本存储在多个服务器上,并使用以下两种可能的策略之一向这些服务器发出接收消息请求,

  • Short Polling : The default behaviour, only a subset of the servers (based on a weighted random distribution) are queried .短轮询:默认行为,只有服务器的一个子集(基于加权随机分布)进行查询
  • Long Polling : Enabled by setting the WaitTimeSeconds attribute to a non-zero value, all of the servers are queried .长轮询:通过将WaitTimeSeconds属性设置为非零值来启用,查询所有服务器

In practice, for my limited tests, I always seem to get one message with short polling just as you did.在实践中,对于我有限的测试,我似乎总是像您一样通过短轮询收到一条消息。

I had the same problem.我有同样的问题。 What is your Receive Message Wait Time for your queue set to?您的队列的接收消息等待时间是多少? When mine was at 0, it only returned 1 message even if there were 8 in the queue.当我的为 0 时,即使队列中有 8 条消息,它也只返回 1 条消息。 When I increased the Receive Message Wait Time, then I got all of them.当我增加接收消息等待时间时,我得到了所有这些。 Seems kind of buggy to me.对我来说似乎有点马车。

I was just trying the same and with the help of these two attributes setMaxNumberOfMessages and setWaitTimeSeconds i was able to get 10 messages.我只是在尝试相同的方法,在这两个属性 setMaxNumberOfMessages 和 setWaitTimeSeconds 的帮助下,我能够获得 10 条消息。

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

Snapshot of o/p: o/p 快照:

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

receiveMessageRequest.withMaxNumberOfMessages(10); receiveMessageRequest.withMaxNumberOfMessages(10);

Just to be clear, the more practical use of this would be to add to your constructor like this:为了清楚起见,更实际的用途是将其添加到您的构造函数中,如下所示:

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

Otherwise, you might as well just do:否则,你也可以这样做:

receiveMessageRequest.setMaxNumberOfMessages(10);

That being said, changing this won't help the original problem.话虽如此,改变这一点无助于解决原来的问题。

Thanks Caoilte!谢谢Caoilte!

I faced this issue also.我也遇到了这个问题。 Finally solved by using long polling follow the configuration here: https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-configure-long-polling-for-queue.html最后通过使用长轮询解决这里的配置: https : //docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-configure-long-polling-for-queue.html

Unfortunately, to use long polling, you must create your queue as FIFO one.不幸的是,要使用长轮询,您必须将队列创建为 FIFO 队列。 I tried standard queue with no luck.我尝试了标准队列但没有运气。

And when receiving, need also set MaxNumberOfMessages.并且在接收时还需要设置MaxNumberOfMessages。 So my code is like:所以我的代码是这样的:

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

Although solved, still feel too wired.虽然解决了,还是觉得太有线了。 AWS should definitely provide a more neat API for this kind of basic receiving operation. AWS 绝对应该为这种基本的接收操作提供更简洁的 API。

From my point, AWS has many many cool features but not good APIs.在我看来,AWS 有很多很酷的功能,但没有好的 API。 Like those guys are rushing out all the time.就像那些家伙一直冲出去一样。

Here's a workaround, you can call receiveMessageFromSQS method asynchronously.这是一种解决方法,您可以异步调用 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);
    });
}

It will return you an array with a given number of messages它将返回一个包含给定消息数的数组

For small task list I use FIFO queue like stackoverflow.com/a/55149351/13678017 for example modified AWS tutorial对于小任务列表,我使用像stackoverflow.com/a/55149351/13678017这样的 FIFO 队列,例如修改后的AWS 教程

            // 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());
            }
        }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM