Leveraging AWS SQS and Lambda for Deferring Heavy Tasks in NodeJS Backend.png

Leveraging AWS SQS and Lambda for Deferring Heavy Tasks in NodeJS Backend (ExpressJS)

Romeo Bellon

By Romeo Bellon

Last update on Jun 26, 2023 · 6 minutes


Introduction

In modern web applications, it's common to encounter heavy tasks that can impact the responsiveness and performance of the backend. One effective approach to address this challenge is to offload these heavy tasks to AWS (Amazon Web Services) services such as SQS (Simple Queue Service) and Lambda. This article explores the advantages of using SQS and Lambda and provides a step-by-step guide on how to defer heavy tasks from a Node.js Express.js backend to these serverless solutions.

Advantages of Deferring Heavy Tasks

Explain the benefits and advantages of deferring heavy tasks to AWS SQS and Lambda:

  1. Improved Performance and Scalability: By offloading heavy tasks to serverless services, the backend can handle concurrent requests more efficiently, improving overall application performance and scalability.
  2. Reduced Backend Latency: Offloading heavy tasks to SQS and Lambda reduces the response time of the backend, enabling faster and more responsive APIs for end-users.
  3. Fault Tolerance and Error Handling: SQS provides durable message storage, ensuring task reliability even during failures. Lambda functions handle task processing, providing built-in retries and error-handling mechanisms.
  4. Cost Optimization: Serverless services like SQS and Lambda follow a pay-per-use model. You only pay for the resources consumed during task processing, resulting in cost optimization compared to maintaining dedicated infrastructure.

Setting Up AWS SQS and Lambda

Provide step-by-step instructions on setting up AWS SQS and Lambda:

1. Creating an SQS Queue

Guide readers through creating an SQS queue, configuring queue settings, and obtaining the necessary credentials for integration with the backend.

To create an SQS (Simple Queue Service) queue, follow these steps:

  1. Access the AWS Management Console and navigate to the SQS service.
  2. Click on "Create queue" to start the queue creation process.
  3. Choose the type of queue you want to create: Standard Queue or FIFO Queue.
      Standard Queue: Offers best-effort ordering and at-least-once delivery of messages.FIFO Queue: Provides strict ordering and exactly-once delivery of messages, supporting message groups, and deduplication.
  4. Provide a name for your queue, ensuring it follows the naming rules specified by AWS.
  5. Configure the queue settings according to your requirements. You can specify options such as:
      Retention period: the number of seconds Amazon SQS retains a message. In other words, if no other program or service has consumed it within this time, the message is removed from the queue.Visibility timeout: the maximum number of seconds a program or service is allowed to process a given message. During this period, it is invisible to other programs or services that might also consume messages from the same queue. Note: the visibility timeout for the SQS queue should be greater than the Lambda function's timeout. Delivery delay: the time in seconds that the delivery of all messages in the queue will be delayed.
  6. Review and confirm the queue details, ensuring they align with your intended configuration.
  7. Click on "Create queue" to create the queue.

Next, I'll explain how to create a Lambda function, define its runtime, set up function triggers, and configure environment variables for seamless integration with the SQS queue.

2. Configuring Lambda Function

Once you have created the SQS queue, the next step is to configure a Lambda function that will process the messages from the queue. Follow these steps to set up the Lambda function for seamless integration with the SQS queue:

  1. Access the AWS Management Console and navigate to the AWS Lambda service.
  2. Click on "Create function" to begin creating a new Lambda function.
  3. Provide a name for your function that is descriptive and meaningful.
  4. Choose the runtime for your Lambda function. Node.js is a popular choice for building serverless applications, but you can select a different runtime based on your specific requirements.
  5. Under "Permissions," select an existing execution role or create a new one to define the AWS Identity and Access Management (IAM) permissions for your Lambda function. These permissions control what actions the Lambda function can perform on your behalf.
  6. Click on "Create function" to create the Lambda function.

Now that you have created the Lambda function, you need to set up triggers to configure it to listen for messages from the SQS queue. Here's how:

  1. In the Lambda function's configuration, scroll down to the "Add triggers" section and click on the "Add trigger" button.
  2. Choose "SQS" as the trigger type.
  3. Select the SQS queue you created earlier from the dropdown list.
  4. Configure the batch size, which determines the number of messages the Lambda function retrieves from the SQS queue in each invocation. This value depends on your application's requirements and workload.
  5. Leave the "Enable trigger" option selected.
  6. Click on "Add" to add the trigger to the Lambda function.

With the trigger set up, the Lambda function will now be invoked whenever new messages arrive in the SQS queue, allowing you to process them asynchronously.

To ensure smooth integration between the Lambda function and the SQS queue, you may also need to configure environment variables in your Lambda function. Environment variables can store configuration values or sensitive information that your function requires. For example, you might store credentials, API keys, or specific configuration settings.

  1. In the Lambda function's configuration, scroll down to the "Environment variables" section.
  2. Click on "Edit" to add or modify environment variables.
  3. Add the necessary key-value pairs for your environment variables.
  4. Click on "Save" to save the changes.

By configuring the Lambda function, setting up triggers, and configuring environment variables, you establish a seamless integration between the Lambda function and the SQS queue. The Lambda function is now ready to receive messages from the queue and process them according to your application's logic.

In the next section, we will explore the steps to implement task deferral in your Node.js Express.js backend, enabling you to enqueue tasks to the SQS queue and leverage the power of Lambda for processing.

3. Implementing Task Deferral in Node.js Express.js

By following these steps, you will be able to enqueue tasks to the SQS queue and leverage the power of Lambda for processing:

  1. Identify Heavy Tasks: Begin by identifying the heavy tasks in your backend that can benefit from deferral. These tasks are typically time-consuming operations, such as image processing, complex calculations, or interactions with external APIs. Deferring these tasks to AWS SQS and Lambda can help offload the processing burden from your backend, ensuring scalability and responsiveness.
  2. Format and Enqueue Tasks to SQS: Once you have identified the heavy tasks, you need to format the task data and enqueue them to the SQS queue. The AWS SDK for Node.js provides convenient methods for interacting with SQS. Using the SDK, you can create a new SQS client, format the task data, and send it to the SQS queue for processing. Remember to include all relevant information needed for task execution, such as parameters, identifiers, or payloads.
  3. Monitor and Handle Errors: Monitoring the task processing and handling errors are crucial aspects of task deferral. AWS CloudWatch provides comprehensive monitoring and logging capabilities for Lambda functions. You can set up CloudWatch Logs to capture execution logs and metrics to track the performance of your Lambda function. Additionally, consider implementing error handling mechanisms, such as capturing and retrying failed tasks, sending notifications, or integrating with centralized error monitoring systems.

Here's an example code snippet to demonstrate the implementation of task deferral in Node.js Express.js:

typescript|1import {SQSClient, SendMessageCommand} from "@aws-sdk/client-sqs";2
3const queueURL = process.env.SQS_QUEUE_URL as string;4
5// initialize an SQS client6const sqsClient = new SQSClient({region: "eu-west-3"});7
8async function sendMessage(MessageGroupId: string, body: any) {9  // define the message body10  const messageBody = JSON.stringify({11    ...body,12    // Amazon SQS continues to keep track of the message deduplication ID13    // even after the message is received and deleted.14    // Adding a timestamp to the message ID ensures that Amazon SQS can15    // differentiate between new and old messages with the same content16    // and thereby prevents the new message from being treated as a17    // duplicate of the old message.18    // (content_based_deduplication=true)19    timestamp: Date.now()20  });21
22  // specify the parameters for the SQS message23  const params = {24    MessageBody: messageBody,25    QueueUrl: queueURL,26    MessageGroupId27  };28
29  try {30    const data = await sqsClient.send(new SendMessageCommand(params));31    console.log({data, body}, "Message sent to SQS");32  } catch (error) {33    console.error({error}, "Failed to send message to SQS");34  }35}36
37export default {sendMessage};

Now, you'll be able to conveniently call sendMessage from any part of your code that requires deferred execution of this task, as shown below:

typescript|1import sqs from "@/services/aws/sqs";2
3// in FIFO queues, messages with the same `groupId` will 4// be processed in sequence (potentially in batches)5await sqs.sendMessage(groupId, {6  // payload 7});

Conclusion

Summarize the advantages of deferring heavy tasks to AWS SQS and Lambda in a Node.js Express.js backend. Highlight the performance improvements, reduced backend latency, fault tolerance, and cost optimization achieved by leveraging these serverless solutions. Encourage readers to explore the detailed implementation guide and start deferring heavy tasks for enhanced application scalability and reliability.

What do you think about this article?

Whether it was helpful or not, we would love to hear your thoughts! Please leave a comment below.