AWS Lambda is an amazing event-based compute service capable of running a function without worrying about the underlying infrastructure. Currently it supports Node.js, Java (and JVM based langs) & Python. It's a brilliant tool for micro-services.
In this article I'll show you how to run some Rust code on AWS Lambda even if Rust is not officially supported.
We will create a simple service that will determine if a string is a valid email address.
Let's start a new cargo project:
λ cargo new email-checker --bin
We will need the regex crate. In Cargo.toml:
[dependencies] regex = "0.1.41"
Then our service implementation in src/main.rs:
extern crate regex; use regex::Regex; use std::env; fn main() { println!("Starting email-checker..."); // Create an email regular expression let re = Regex::new(r"^\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$").unwrap(); // Match the first argument against the regular expression match env::args().nth(1) { // We have an argument Some(email) => { if re.is_match(&email) { println!("{} is a valid email.", email); } else { println!("{} is NOT a valid email.", email); } } // No argument provided None => { println!("Please provide a string to test."); return; } }; };
My machine is running OS X, AWS Lambda runs Linux. I tried to cross-compile a Linux binary on Darwin but that was too much of a hassle. In order to get the same environment as my lambda function will run on, I simply created an EC2 t2.micro instance to compile my code.
Create an Amazon Linux EC2 instance, ssh onto it and run:
λ sudo yum install git
λ sudo yum groupinstall "Development Tools"
to get a working development environment. Then clone your email-checker repo and run:
λ cargo build --release λ cp target/release/email-checker ./email-checker-linux
We now have a working Linux binary w00t! Commit and push the binary to your repo, you can terminate the instance.
Since Rust is not supported by AWS Lambda, we will write a simple Javascript module that will spawn a child process with our Rust binary. That's the main trick of this article :). Note that we could ship a Haskell, Go, OCaml or whatever binary the same way.
Let's create a main.js at the root of our project:
var child_process = require('child_process'); exports.handler = function(event, context) { // event is the JSON we provide to our lambda function. More on this later. console.log(event["email"]); // spawn a child process with our email-checker-linux binary and the // event["email"] value for our argument. var proc = child_process.spawn('./email-checker-linux', [ event["email"] ], { stdio: 'inherit' }); proc.on('close', function(code) { if(code !== 0) { return context.done(new Error("Process exited with non-zero status code")); } context.done(null); }); }
In order to upload our code to AWS lambda, we just have to create a zip
file containing our main.js and our email-checker-linux binary.
Log in to the AWS console, click on Lambda in the Compute section
and click Get started now. We are then shown a list of lambda
functions blueprints. We will not use a blueprint for our example so
click Skip. Next we need to configure our lambda function.
Fill in the name of the function, its description and choose the Node.js runtime.
Figure 1: Setup lambda function
In the Lambda function code section, choose Upload a .ZIP file and
upload the file we created previously.
In Lambda function handler and role, use main.handler for the
handler and choose the Basic execution role. This will open a popup
prompting you to create a new IAM Role, just allow with the default
settings.
Figure 2: Setup IAM role
Back on our function setup, leave the Advanced settings as is and
click Next.
Finally, we can review and create the function. Congratulations you created your first AWS Lambda function.
On the lambda function screen click Actions then
Configure test event. Here we can write some JSON that will be
received by our Node.js handler as the event parameter.
{
"email": "karl@marx.com"
}
Click Save and test. This will execute our lambda function. If you
click Monitoring, you can see that we ran our function once.
Figure 3: Lambda monitoring
To view the result, click View logs in CloudWatch. We're presented
with a list of log lines.
Figure 4: Log lines
Click the first line and boom karl@marx.com is indeed a valid email.
Figure 5: Lambda function result
Our email checking micro-service is still lacking an interface, we could use Amazon API gateway to create a simple endpoint where we could POST the string we want to check and return a proper response for example.
That's it! We successfully ran some Rust code on AWS Lambda. Have fun Rustaceans :)
You can find the full code and the Linux binary here.