Expanding Your Tech Stack with AWS Lambdas

Development

Reading Time: 5 minutes

Let’s face it. Debugging performance issues is hard, but fixing them is even harder.

Let’s say you’ve found the offending code that’s slowing your app down. Eventually there comes a time when you find out that this speed bump of code is synchronous — or linearly executing. One of the most effective ways to remedy these problematic sections of code is to delegate the heaviest workloads for processing to a later time and place.

While there’s an endless amount of workload delegation solutions out there, the idea of executing code on third-party servers — also known as serverless functions — has become increasingly popular in recent years.

Serverless functions are incredibly useful because we can configure the time and frequency of execution by which these workloads are processed. Furthermore, we only pay for the time and computing power that we use. There’s no need for an ever-running server that’s consuming hosting costs even when it’s not in use.

Serverless Functions in Amazon Web Services

In Amazon Web Services (or AWS), severless functions are known as Lambdas. While Lambdas and other serverless functions give us the benefit of executing code on other machines, there are restrictive terms on how we can do it.

Since we’re technically renting hardware — and software — from AWS, they get to determine the hardware specs and environment that the code is run on.

For Amazon, this means running and executing code on an Ubuntu (Linux) environment. There are also specific limits about the AWS Lambda deployment and execution environment that we need to think about.

While they’re all important, I want to talk about some limits that will determine how we approach designing and implementing our functions.

Memory and time limits

While we’re ultimately trying to delegate work to AWS Lambdas, we need to do it in a manner that fits under the 128MB memory usage limit and execution limit. Each function must also take less than 300 seconds (five minutes) to execute.

While you can certainly accomplish a lot of work in five minutes, I’ve found it useful to design Lambda functions around a more modular focus. This means designing the function to process smaller units of work through a Lambda multiple times instead of sending a giant batch of data to be executed in one fell swoop.

With a more modular Lambda implementation, we should be able to process whatever we need well under these limits.

Temporary storage

Storage is also a bit interesting in AWS Lambdas. We can also only write up to 512MB in one portion of the Lambda’s filesystem: /tmp.

While we can certainly model data in a Lambda, we depend on external resources to retrieve and permanently store the execution result data. We’re ultimately concerned with creating a piece of code that calculates the result of something and sends it off to another place to be stored.

Deployment package size

Another thing that’s worth noting is the deployment package limit. While the files with code we’ve written should easily fit under that limit, we can’t forget about dependencies.

AWS Lambdas require us to have each dependency extracted within our deployment package. So we need to ensure that the sum of our code and dependencies fits under this limit!

Language limitations

Finally, one of the biggest constraints is that only certain languages are allowed to be executed in a Lambda. For AWS Lambdas, these languages are (at the time of writing) Python, Go, JavaScript, and Java.

If an application is written in one of these languages, you’re in luck! All you have to do is import the code, and you’re good to go.

However, I want to walk through why using Lambdas still makes sense even when your app isn’t written in one of these languages.

An Example with Ruby and Python

A lot of my recent work has been based around a Python Lambda called by a Ruby-based application. So I’m going to demonstrate an example using those two languages.

Python and Ruby are both dynamic languages. While AWS doesn’t offer Ruby support for Lambdas, they do support Python. Writing a Python Lambda for a Ruby codebase can make a lot of sense since they’re similar in style and structure. Amazon also has a wonderful Ruby SDK that we’ll use for calling and managing our Lambdas.

Let’s start by writing the Python Lambda:

index.py

def handler(event, context):
  input_message = event.get('message')
  print(input_message)
  return {
    'message': 'Well, hey there Ruby application!'
  }

You can follow Amazon’s tutorial on how to deploy this piece of code as a Lambda. Once set up, we’ll need a few pieces of information about the Lambda:

  • The AWS Region where the Lambda is deployed
  • Your AWS Access Key and Access Secret Key
  • The name of the Lambda

With these pieces of information in hand, we can start writing the Ruby application. Before you start, remember to add the AWS Ruby SDK to your project’s Gemfile.

app.rb

require ‘aws-sdk’
require 'json'
     
credentials = Aws::Credentials.new('access-key', 'access-key-secret')
     
lambda_client = Aws::Lambda::Client.new(
  region: 'lambda-aws-region',
  credentials: credentials
)
    
app_payload = { 
  message: "Hello Python Lambda!"
}
     
response = lambda_client.invoke({
  function_name: "SampleAWSFunction",
  invocation_type: "RequestResponse",
  payload: app_payload
})
     
parsed_response = JSON.parse(resp.payload.string)
puts parsed_response

With this in mind, we can now run app.rb and get a live response from our Lambda!

Wrapping Up

With this base example, we now have the means to delegate more complex Ruby-based code into a Lambda function in any language that AWS supports.

While our example is more preferential toward Python, the freedom that AWS and other serverless function providers give is the ability to choose the best language for the job at hand.

Need to build something that’s more performant with threads? Maybe try using a language like Java or Go for your function. Want to stay in something similar to Ruby? Stick with this Python template or give JavaScript a try!

While choosing a language outside of AWS’s stack and running your own solution is definitely attractive in many ways, the stability, cost, and efficiency of using AWS Lambdas are the strongest selling points of the service. To me, these reasons alone provide an efficient and cost-effective means to help you better balance synchronous execution bottlenecks in your applications.

Another thing I’ve found interesting in working with AWS Lambdas is that everyone has their own unique solution and implementation of using them.

Each architecture takes time, trial, and error to develop though. If done right, the investment and frustration pay off immensely in solving issues with application speed and execution times.

Ultimately, we need to weigh the costs of utilizing Lambdas alongside the time that they free up on our main application servers. You may eventually find yourself fully utilizing serverless architecture one day, too!

Either way, learning more about serverless solutions like AWS’s Lambda Functions will give you another means for solving speed and performance problems in your growing software applications. It may not always be the remedy, but it’s an effective solution for helping things move faster and stronger into the future.

Subscribe via Email

Over 60,000 people from companies like Netflix, Apple, Spotify and O'Reilly are reading our articles.
Subscribe to receive a weekly newsletter with articles around Continuous Integration, Docker, and software development best practices.



We promise that we won't spam you. You can unsubscribe any time.

Join the Discussion

Leave us some comments on what you think about this topic or if you like to add something.