Getting Started

Install

Because this project is still in an early (but functional!) stage, it has not yet been published to the crates registry. You will therefore need to depend directly on the Github repository. Add the following to the [dependencies] section in your Cargo.toml file.

aws_lambda = { git = "https://github.com/srijs/rust-aws-lambda" }

Create

The start function will launch a runtime which will listen for messages from the lambda environment, and call a handler function every time the lambda is invoked. This handler function can be async, as the runtime itself is based on top of futures and tokio.

extern crate aws_lambda as lambda;

fn main() {
    // start the runtime, and return a greeting every time we are invoked
    lambda::start(|()| Ok("Hello ƛ!"))
}

Alternatively, the gateway module contains functionality to implement a lambda function that can be used to build an API Gateway API with Lambda Proxy Integration.

extern crate aws_lambda as lambda;

fn main() {
    lambda::gateway::start(|_req| {
        let res = lambda::gateway::response()
            .status(200)
            .body("Hello ƛ!".into())?;
        Ok(res)
    })
}

Input

To provide input data to your handler function, you can change the type of the argument that the function accepts. For this to work, the argument type needs to implement the serde::Deserialize trait (most types in the standard library do).

extern crate aws_lambda as lambda;

use std::collections::HashMap;

fn main() {
    lambda::start(|input: HashMap<String, String>| {
        Ok(format!("the values are {}, {} and {}",
            input["key1"], input["key2"], input["key3"]))
    })
}

Additionally, the event module provides strongly-typed lambda event types for use with AWS event sources.

For example, this would print out all the S3Event record names, assuming your lambda function was subscribed to the proper S3 events:

extern crate aws_lambda as lambda;

use lambda::event::s3::S3Event;

fn main() {
    lambda::start(|input: S3Event| {
        let mut names = Vec::new();
        for record in input.records {
            names.push(record.event_name);
        }
        Ok(format!("Event names:\n{:#?}", names))
    })
}

The types in the event module are automatically generated from the official Go SDK and thus are generally up-to-date.

Dealing with null and empty strings in lambda input

The official Lambda Go SDK sometimes marks a field as required when the underlying lambda event json could actually be null or an empty string. Normally, this would cause a panic as Rust is much more strict.

The event module deals with this reality by marking all required json string fields as Option<String> in Rust. Json null or the empty string are deserialized into Rust structs as None.

Context

While your function is running you can call Context::current() to get additional information, such as the ARN of your lambda, the Amazon request id or the Cognito identity of the calling application.

extern crate aws_lambda as lambda;

fn main() {
    lambda::start(|()| {
        let ctx = lambda::Context::current();

        Ok(format!("Hello from {}!", ctx.invoked_function_arn()))
    })
}

Logging

The aws_runtime crate bundles its own logger, which can be used through the log facade.

To initialize the logging system, you can call logger::init().

extern crate aws_lambda as lambda;
#[macro_use] extern crate log;

fn main() {
    lambda::logger::init();

    lambda::start(|()| {
        info!("running lambda function...");

        Ok("Hello ƛ!")
    })
}

Deploy

Note: These instructions will produce a static musl binary of your rust code. If you are looking for non-musl binaries, you might try docker-lambda.

To deploy on AWS lambda, you will need a zip file of your binary. If you are running Linux, this may be as simple as running cargo --target x86_64-unknown-linux-musl if your dependencies do not require OpenSSL. If you are on non-Linux platforms, the binary needs to built against amazonlinux.

A Dockerfile is provided as an example and will work for single project binaries that need OpenSSL. The Dockerfile is based off of rust-musl-builder.

docker pull amazonlinux
docker build --force-rm -t aws-lambda:latest --build-arg SRC=example -f docker/dockerfile .
docker run -v /tmp/artifacts:/export --rm aws-lambda:latest

Build your lambda function and upload your zip file. Change the lambda runtime to go 1.x and set the handler function to the name of your application as defined in your Cargo.toml.

SSL considerations

If your binary requires SSL, add the following environment variables:

SSL_CERT_DIR=/etc/ssl/certs
SSL_CERT_FILE=/etc/ssl/certs/ca-bundle.crt

If you are still running into SSL issues using the Docker image or are building directly on Linux, you may need to modify your application per https://github.com/emk/rust-musl-builder#making-openssl-work.

When using rusoto it is highly suggested to use the crate’s rustls feature instead of building OpenSSL.

error_chain

In general we suggest you use the failure crate for error handling. If you are instead using error_chain in your rust code, you will also have to disable default features to use the example musl Dockerfile. Add the following to your Cargo.toml:

[dependencies.error-chain]
version = "~0.12"
default-features = false

Troubleshooting

To help you debug your lambda function, aws_lambda integrates with the failure crate to extract stack traces from errors that are returned from the handler function.

In order to take advantage of this, you need to compile your program to include debugging symbols. When working with cargo using --release, you can add the following section to your Cargo.toml to include debug info in your release build:

[profile.release]
debug = true

Next, you want to instruct the runtime to collect stack traces when errors occur. You can do this by modifying the configuration of your function in AWS to set the RUST_BACKTRACE environment variable to 1.

After both of these changes have been deployed, you should start to see stack traces included in both the error info returned from invocations, as well the CloudWatch logs for your function.