MattG
MattG

Reputation: 6385

Does AWS SQS Long poll return early if a message is received?

If I use SQS long polling and set the "WaitTimeSeconds" to say 10 seconds and "MaxNumberOfMessages" to 1, and a single message is delivered to the queue after say 0.1 seconds, will the call to sqs.receiveMessage() return immediately at that point, or should it not return until the 10 seconds of "WaitTimeSeconds" have elapsed?

In my testing the call to sqs.receiveMessage() seems to not return until the full duration of "WaitTimeSeconds" has elapsed.

Here is the code:

// Load the AWS SDK for Node.js
var AWS = require("aws-sdk");

const fmReqQ = "https://sqs.ap-southeast-2.amazonaws.com/myactid/fmReqQ";
const fmRspQ = "https://sqs.ap-southeast-2.amazonaws.com/myactid/fmRspQ";

const SydneyRegion = "ap-southeast-2";

var credentials = new AWS.SharedIniFileCredentials({ profile: "myprofile" });
AWS.config.credentials = credentials;

// Set the region
AWS.config.update({ region: SydneyRegion });

// Create an SQS service object
var sqs = new AWS.SQS({ apiVersion: "2012-11-05" });

async function sendRequest() {
  var sendParams = {
    MessageBody: "Information of 12/11/2016.",
    QueueUrl: fmReqQ,
  };

  try {
    data = await sqs.sendMessage(sendParams).promise();
    console.log("Success, request MessageId: ", data.MessageId);
  } catch (err) {
    console.log("Error", err);
  }
}

async function doModelling() {
  console.time("modelling");
  await sendRequest();
  await receiveResponse();
  console.timeEnd("modelling");
}

async function receiveResponse() {
  var receiveParams = {
    AttributeNames: ["SentTimestamp"],
    MaxNumberOfMessages: 1,
    MessageAttributeNames: ["All"],
    QueueUrl: fmRspQ,
    WaitTimeSeconds: 1,
  };

  let data = null;
  try {
    data = await sqs.receiveMessage(receiveParams).promise();
    console.log("Success, response MessageId: ", data);
  } catch (err) {
    console.log("Error", err);
  }
}

doModelling();

When I set "WaitTimeSeconds: 3" I get output:

Success, request MessageId:  e5079c2a-050f-4681-aa8c-77b05ac7da7f
Success, response MessageId:  {
  ResponseMetadata: { RequestId: '1b4d6a6b-eaa2-59ea-a2c3-3d9b6fadbb3f' }
}
modelling: 3.268s

When I set "WaitTimeSeconds: 10" I get output:

Success, request MessageId:  bbf0a429-b2f7-46f2-b9dd-38833b0c462a
Success, response MessageId:  {
  ResponseMetadata: { RequestId: '64bded2d-5398-5ca2-86f8-baddd6d4300a' }
}
modelling: 10.324s

Notice how the elapsed time durations match the WaitTimeSeconds.

From reading about AWS SQS long polling it says it long polling "Return messages as soon as they become available."

I don't seem to be seeing the messages "as soon as they become available", I seem to be noticing the sqs.receiveMessage() call always taking the duration set in WaitTimeSeconds.

As you can see in the sample code, I have set MaxNumberOfMessage to 1.

Upvotes: 4

Views: 1856

Answers (3)

John Rotenstein
John Rotenstein

Reputation: 269081

Using ReceiveMessage() with Long Polling will return as soon as there is at least one message in the queue.

I'm not a Node person, but here's how I tested it:

  • Created an Amazon SQS queue
  • In one window, I ran:
aws sqs receive-message --queue-url https://sqs.ap-southeast-2.amazonaws.com/123/foo --visibility-timeout 1 --wait-time-seconds 10
  • Then, in another window, I ran:
aws sqs send-message --queue-url https://sqs.ap-southeast-2.amazonaws.com/123/foo --message-body bar

The receive-message command returned very quickly after I used the send-message command.

It is possible that your tests are impacted by messages being 'received' but marked as 'invisible', and remaining invisible for later tests since your code does not call DeleteMessage(). I avoided this by specifically stating --visibility-timeout 1, which made the message immediately reappear on the queue for the next test.

The number of messages being requested (--max-number-of-messages) does not impact this result. It returns as soon as there is at least one message available.

Upvotes: 2

MattG
MattG

Reputation: 6385

The value I was specifying for "WaitTimeSeconds" determines the duration of the sqs.receiveMessage() call because there were no messages on my queue, so the sqs.receiveMessage() call will wait for duration specified by "WaitTimeSeconds".

Upvotes: 0

MattG
MattG

Reputation: 6385

I set the "WaitTimeSeconds" to 0, I seem to get the behaviour that I am after now:

Success, request MessageId:  9f286e22-1a08-4532-88ba-06c88be3dbc3
Success, response MessageId:  {
  ResponseMetadata: { RequestId: '5c264e27-0788-5772-a990-19d78c8b2565' }
}
modelling: 307.884ms

Upvotes: 0

Related Questions