chrismitchellonline

AWS Lambda Destinations - A Real World Example

2020-01-10

An AWS Lambda Destination is a way to route the results of a Lambda function to another AWS service such as SQS, SNS, or another Lambda function. This can help simplify our code by keeping to a Separation of concerns programming pattern, which ultimately will help us maintain a microservices architecture.

Real World Example

Let’s take the real world example of an ecommerce order. Typically an order system would include accepting payment, updating inventory, and potentially many more aspects of placing an order. In a microservice environment there would be a Lambda function to handle each of these concerns. Next we will take a look at how we can achieve this with and without AWS Lambda Destinations.

Before Destinations - One Lambda Function

We could create a Lambda function that synchronously submits orders to each piece of the order system and then responds with a success or failure. The calling system, a website for example, would wait for the response. Using async/await to maintain synchronous calls, our code might look like:

//place order and update inventory. 
//If error, return error to user
//otherwise return ok
try{
    const order;
    const paymentResults = await paymentObject.submit(order);
    const updateInventory = await inventory.update(order);
    const sendShipment = await shipment.send(order);
    //perform more order tasks here
}
catch(error){
    //return error
}

//no error, return ok

This simplistic example presents a few problems:

  1. While we are separating out our concerns in objects, we do not achieve a microservice architecture with our single use Lambda function.
  2. The more complex your order system is, the more complex this code can get.
  3. The end system must wait for all of the tasks to complete before returning.

Before Destinations - A Better Approach

The previous example simply would not scale in a complex environment. Still without using Lambda Destinations we can improve on our example to use other AWS services, mainly AWS Simple Queue Service (SQS).

Instead of waiting for each of our tasks to complete, we can instead complete our critical tasks and then write messages to an appropriate SQS queue to be processed later, then return a response faster. That code might look like this:

//place order, then send message to order queue 
//If error, return error to user
//otherwise return ok
try{
    const order;
    const paymentResults = await paymentObject.submit(order);
    await AWS.SNS.send(orderUpdate);
    //send other queue messages here
}
catch(error){
    //return error
}

//no error, return ok

This example will allow us to implement a better microservice architecture with an individual Lambda function to handle each of our concerns based on SQS queues. For example, a Lambda inventory function can read from an order SQS queue to update when a new order is available on the queue.

Lambda Destinations

Our example processing orders by implementing SQS would be a viable solution that scales, but now we can introduce Lambda Destinations to further simplify our order system. To further understand Lambda Destinations, AWS documentation explains:

With Destinations, you can route asynchronous function results as an execution record to a destination resource without writing additional code. An execution record contains details about the request and response in JSON format including version, timestamp, request context, request payload, response context, and response payload.

Essentially, we can call other systems in our AWS stack with the results of our place order results instead of placing items on an SQS queue to be processed later. This simplifies things by removing the queue system all together, instead we can send data to our relative microservices directly in an asynchronous way, which will not slow down our response times.

We can add a destination for our Lambda function from the web console or the AWS CLI. From the web console, visit the Lambda configuration page, and under Designer click + Destination.

Lambda Destination

Or by using the AWS CLI tools, see the following example, where my Lambda function is order and my destination function is update-inventory:

aws lambda update-function-event-invoke-config \
    --function-name order \
    --destination-config '{"OnSuccess":{"Destination": "arn:aws:lambda:us-east-1:xxx:function:update-inventory"}}'

With our ecommerce example, we will always want to update our inventory whenever we have a successful order. We can now tell our order function to send its response to our inventory function whenever the order is successful.

OnSuccess and OnFailure

In the ecommerce example we are calling a destination on order success. We can also send to destinations on failure. This allows us to extract our error handling out of our services. For example, if an order does not have inventory, when our update-inventory function fails, we can send the failure to a destination that can roll back the order. This can be a separate microservice, essentially decoupling the rollback function from the update-inventory function.

Notifications

Because Lambda Destinations can send responses to AWS Simple Notification System (SNS) we can send out notifications for successes or failures, again without modifying our concerned Lambda function. We could create an SNS topic for all new orders, and automatically send a notification each time an order is processed.

Conclusion

In this article we discussed how to use AWS Lambda Destinations to simplify an ecommerce order process. While the examples in this article are meant to be simplistic, I hope that the concepts of how to use not only Destinations but SQS are apparent and will help in your development efforts.

Have questions about how to use AWS services like Lambda and SQS to simplify your development process? Or are you working on an ecommerce system and are having difficulties scaling? I’d love to hear from you in the comments below or by email: chris@chrismitchellonline.com

Sources

comments powered by Disqus