Bill
Bill

Reputation: 5150

What is the best way to poll for messages from Amazon Web Services SQS

What is the best way to poll for messages from Amazon Web Services SQS? I want to handle the messages as soon as they are in the queue and don't really want to poll every second unless this is the only option?

setInterval(run(), 1000); I get the error

const run: () => Promise<void>
//---------------------------------
No overload matches this call.
  Overload 1 of 2, '(callback: (...args: any[]) => void, ms: number, ...args: any[]): Timeout', gave the following error.
    Argument of type 'Promise<void>' is not assignable to parameter of type '(...args: any[]) => void'.
      Type 'Promise<void>' provides no match for the signature '(...args: any[]): void'.
  Overload 2 of 2, '(handler: TimerHandler, timeout?: number, ...arguments: any[]): number', gave the following error.
    Argument of type 'Promise<void>' is not assignable to parameter of type 'TimerHandler'.
      Type 'Promise<void>' is missing the following properties from type 'Function': apply, call, bind, prototype, and 5 more.ts(2769)`

my code...

const QueueUrl = process.env.SQS_QUEUE_URL;
const params = {
  AttributeNames: ['SentTimestamp'],
  MaxNumberOfMessages: 10,
  MessageAttributeNames: ['All'],
  QueueUrl,
  VisibilityTimeout: 20,
  WaitTimeSeconds: 0,
};
const sqs = new SQSClient({ region: process.env.SQS_REGION });

const run = async () => {
  try {
    const data = await sqs.send(new ReceiveMessageCommand(params));
    if (data.Messages) {
      for (const val of data.Messages) {
        const address = val.MessageAttributes.Address.StringValue;
        const amount = Number(val.MessageAttributes.Amount.StringValue);
        createTransaction(address, amount);
        const deleteParams = {
          QueueUrl,
          ReceiptHandle: val.ReceiptHandle,
        };
        try {
          await sqs.send(new DeleteMessageCommand(deleteParams));
        } catch (err) {
          // tslint:disable-next-line: no-console
          console.log('Message Deleted', data);
        }
      }
    } else {
      // tslint:disable-next-line: no-console
      console.log('No messages to delete');
    }
  } catch (err) {
    // tslint:disable-next-line: no-console
    console.log('Receive Error', err);
  }
};
run();

Upvotes: 1

Views: 1929

Answers (2)

John Rotenstein
John Rotenstein

Reputation: 269081

When calling ReceiveMessage, you can specify WaitTimeSeconds up to 20 seconds. This is known as Long Polling.

It works like this:

  • If there are messages in the queue, the call will return immediately with up to 10 messages
  • If there are no messages in the queue, but some appear within the WaitTimeSeconds period, the call will return as soon as messages are available
  • If there were no messages in the queue for the entire WaitTimeSeconds period, then the call will return with no messages

This means you can call ReceiveMessage in a loop, but if there are no messages, it will wait up to 20 seconds before it returns. This is better than "polling every second".

Alternatively, you could put your code in an AWS Lambda function and configure the Amazon SQS queue as a trigger for the function. When a message is sent to the queue, the Lambda function will automatically be invoked, with the message(s) being passed into the function via the event parameter (without needing to call ReceiveMessage).

Upvotes: 2

smac2020
smac2020

Reputation: 10704

If you want to retrieve messages on a regular basis (for example, every 2-3 mins), one way you can achieve this use case is to write a Lambda function that uses the SQS API and then call receiveMesage (what you do with the messages is up to you). Then schedule the Lambda function to be invoked using Cloud Watch event. You can use a CRON expression to define how often the Lambda function is invoked.

Upvotes: 1

Related Questions