πŸ“¦ πŸš€ a smooth-talking smuggler of Rust HTTP functions into AWS lambda

Overview

lando Build Status Coverage Status crates.io docs.rs Master API docs

🚧 maintenance mode ahead 🚧

As of this announcement AWS not officialy supports Rust through this project. As mentioned below this projects goal was to work with and not against the strong lambda ecosystem. As a result I'm merging efforts with the official AWS Rust lambda project. Thank you for your interest and support with lando! We've still got a great road ahead.

Run Rustlang http applications on AWS Lambda with API Gateway

#[macro_use] extern crate lando;

gateway!(|_, _| {
  Ok("πŸ‘‹ Hello, what have we here?")
});

πŸ€” about

Lando is a crate for building serverless Rustlang HTTP applications.

The rustlang ecosystem has some really great HTTP server crates. Most of them bundle servers that parse HTTP messages, listen on ports and manage network connections leaving it up to you to manage hosting, scaling, monitoring and operations in addition to your application code.

Lando is different. Lando's sole focus is on writing applications. It shifts the undifferentiated heavy lifting and responsibility of managing servers to AWS. Put more directly, AWS lambda free's you up to run code without thinking about servers.

Lando's embraces the Rust community's http crate as it's core interface for API Gateway. Lando extends the existing work of the crowbar crate which provides needed lower level machinery for easily deploying Rust applications with one of lamdba's lowest overhead runtimes, Python 3.6. Lando targets API Gateway triggered lambdas. Checkout crowbar if you're building applications for one of Lambda's many other triggers.

A large and mature ecosystem of tooling for AWS lambda exists and works well, including workflow tools like the serverless toolkit. Because these tools are likely to already exist within organizations, the barrier of introducing Rustlang into their arsenel will be much lower. Lando does not intend to replace these tools but instead to work well with them πŸ‘«πŸΎ.

πŸ‘ What makes Rust a good choice for Lambda applications

The AWS cost model for lambda is largely based on two factors: memory size and speed. The CPU provided to applications is proportional to memory size requested. Lambda has a pay per usage cost model billing favoring applications that are both fast and have low memory overheads.

As a systems language, Rust is designed specifically for these kinds of needs. Rust has a very tiny runtime, manages memory very effciently, and is extremely fast.

As a highly embeddable language, its interop story for runtimes like python's is πŸ’– . Be mindful that lando assumes you're exposing these applications through AWS API gateway which has its own generous pricing model.

πŸ“¦ install

Add the following to your cargo project's Cargo.toml file.

[lib]
crate-type = ["cdylib"]

[dependencies]
lando = "0.2"

πŸ’‘ The crate-type property links and produces a shared object ( *.so ) file allowing your rustlang application to compiled to linux native binary that can be invoked from the AWS python 3.6 lambda runtime

πŸ‘©β€πŸ­ create

Lando exports a macro named gateway! which in turn, exports a Rust function or closure to a cpython native binary extention making it ready for use within an AWS Lambda.

#[macro_use] extern crate lando;

gateway!(|request, _context| {
  println!("{:?}", request);
  Ok("hello lambda")
});

This closure accepts an http::Request with a lando::Body. This Body type can be dereferenced as a slice of bytes if needed.

For more more in-depth details see this project's crate documentation.

Lando also supports a function attribute method for exporting a function as a lambda ready fn.

#[macro_use] extern crate lando;

use lando::{Request, LambdaContext, IntoResponse, Result};

#[lando]
fn example(
  _: Request,
  _: LambdaContext
) -> Result<impl IntoResponse> {
   Ok("hello lambda")
}

πŸ”¬ testing

Since these functions are just Rust you can test your application with the built in unit testing framework

In addition you can also integration test your functions by invoking them locally

🐳 Lambda CI

The lambda CI docker project contains docker images that mirror the AWS lambda runtimes. This enables you to build and test your lambda projects locally environments that match with AWS's.

Build

In order to invoke your function in a Lambda compatible environment you must first build it in one.

$ docker run --rm \
  -v ${PWD}:/code \
  -v ${HOME}/.cargo/registry:/root/.cargo/registry \
  -v ${HOME}/.cargo/git:/root/.cargo/git \
  -e CARGO_FLAGS="--features lando/python3-sys" \
  softprops/lambda-rust

This results in a native linux binary .so file under thetarget/lambda/release directory

Invoke

You can use the lambci/lambda:python3.6 docker images to invoke your lambda locally

This example provides the lambda's event though std in by piping a file, in this example a file called example_request.json. Feel free to create your own mock inputs.

cat example_request.json
{
  "path": "/test/hello",
  "headers": {
    "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
    "Accept-Encoding": "gzip, deflate, lzma, sdch, br",
    "Accept-Language": "en-US,en;q=0.8",
    "CloudFront-Forwarded-Proto": "https",
    "CloudFront-Is-Desktop-Viewer": "true",
    "CloudFront-Is-Mobile-Viewer": "false",
    "CloudFront-Is-SmartTV-Viewer": "false",
    "CloudFront-Is-Tablet-Viewer": "false",
    "CloudFront-Viewer-Country": "US",
    "Host": "wt6mne2s9k.execute-api.us-west-2.amazonaws.com",
    "Upgrade-Insecure-Requests": "1",
    "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.82 Safari/537.36 OPR/39.0.2256.48",
    "Via": "1.1 fb7cca60f0ecd82ce07790c9c5eef16c.cloudfront.net (CloudFront)",
    "X-Amz-Cf-Id": "nBsWBOrSHMgnaROZJK1wGCZ9PcRcSpq_oSXZNQwQ10OTZL4cimZo3g==",
    "X-Forwarded-For": "192.168.100.1, 192.168.1.1",
    "X-Forwarded-Port": "443",
    "X-Forwarded-Proto": "https"
  },
  "pathParameters": {
    "proxy": "hello"
  },
  "requestContext": {
    "accountId": "123456789012",
    "resourceId": "us4z18",
    "stage": "test",
    "requestId": "41b45ea3-70b5-11e6-b7bd-69b5aaebc7d9",
    "identity": {
      "cognitoIdentityPoolId": "",
      "accountId": "",
      "cognitoIdentityId": "",
      "caller": "",
      "apiKey": "",
      "sourceIp": "192.168.100.1",
      "cognitoAuthenticationType": "",
      "cognitoAuthenticationProvider": "",
      "userArn": "",
      "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.82 Safari/537.36 OPR/39.0.2256.48",
      "user": ""
    },
    "resourcePath": "/{proxy+}",
    "httpMethod": "GET",
    "apiId": "wt6mne2s9k"
  },
  "resource": "/{proxy+}",
  "httpMethod": "GET",
  "queryStringParameters": {
    "name": "me"
  },
  "stageVariables": {
    "stageVarName": "stageVarValue"
  }
}

Invoke the resulting function using docker providing the contexts of the mock event as stdin.

$ docker run \
  -i -e DOCKER_LAMBDA_USE_STDIN=1 \
  --rm \
  -v \
  "$PWD/target/lambda/release":/var/task lambci/lambda:python3.6 \
  liblambda.handler < example_request.json

πŸš€ deploy

In order to deploy your app you will need to build it within a runtime compatible with the lambda python 3.6 env.

⚑ serverless framework

The recommended way to get started is with the serverless framework. A serverless framework plugin exists to facilitate rapid development/deployment cycles.

You can bootstrap a new deploy ready lando application by using this serverless project template

$ serverless install \
  --url https://github.com/softprops/serverless-lando \
  --name my-new-service

🐳 docker

A docker image is provided for convenience which replicates the AWS python3.6 env with rustlang build tooling.

It's focus is on applications targeting stable versions of Rust.

$ docker run --rm \
  -v ${PWD}:/code \
  -v ${HOME}/.cargo/registry:/root/.cargo/registry \
  -v ${HOME}/.cargo/git:/root/.cargo/git \
  -e CARGO_FLAGS="--features lando/python3-sys" \
  softprops/lambda-rust

This will result in a deployable .so build artifact under a target/lambda directory

This file can then be zipped up for AWS lambda deployment.

πŸƒ performance

Performance analysis for lambda applications, or any application, varies based on your usecase. In the specific case of lando, factors include

  • your use of api gateway (the HTTP loadbalancing that AWS runs that invokes your functions)
  • your lambda configuration (allocation of memory and attachment to resources like VPC's)
  • lambda translation layer (translating between python and rust)
  • your application (that's you!)

The serverless mindset is an explicit tradeoff of control runtime for focus on application.

Your application is very capable of running in double digit milliseconds.

Lando's goal is to provide a minimally invasive translation layer between the native python events to native rustlang http types and back

A benchmark test exists to measure that translation time with a typical gateway event which reports a typical (8.65 ΞΌ (micro) second results +/- 4 ΞΌ seconds) This is not likely going to be the bottleneck of your application

test gateway_conversion ... bench:       8,652 ns/iter (+/- 4,193)

πŸ’± Concurrency

Consideration for concurency should be noted when approaching performance with AWS lamda.

AWS Lamda is expressly horizontal scaled. You scale not by spawning more threads in a running process ( scaling up ↕️ ) but by spawning more lambdas ( scaling out ↔️ ).

A key benefit of AWS lambda is that the platform handles concurrency by spawning more instances of your function for you. This results in some economical advantages in they way you only pay for what you use. Bear in mind you are billed at intervals of 100 milliseconds, so the usefulness optimizing for cost is lost once you've dipped below that point

Examples in the wild

  • slack standup slack command webhook for automating standups
  • jirabars github webhook that fills in jira placeholder info based on branch names
  • barbershop github webhook that deletes branches after pr

🚧 planned changes

(none)

Doug Tangren (softprops) 2018

Comments
  • Reexport http crate

    Reexport http crate

    As this crate expressly promotes http crate interfaces it's common that applications need to add the http and extern it to use interfaces like statuscode method ect. Let's make that a little less of a hassle

    opened by softprops 1
  • Fix example for running lando docker image

    Fix example for running lando docker image

    The example is proper on the root README, but is wrong on Docker hub and the README in the builder folder. Should probably be fixed on the Docker hub docs too. Can be very confusing for newcomers.

    opened by veryjos 1
  • write a post on what I learned

    write a post on what I learned

    I learned a lot about serverless framework, aws lambda, crowbar, cpython, cargo, and the http crate while writing this library. leaving this issue here as a reminder that I should share some of that experience in blog post form so others can benefit and maybe take that learning a step further

    opened by softprops 1
  • Look into upcoming crowbar event types

    Look into upcoming crowbar event types

    https://github.com/ilianaw/rust-crowbar/issues/32 basically provides the value this crate adds out of the box. Find a way to compliment rather than conflict with those changes to enhance the rust lambda community

    opened by softprops 1
  • hashmap to strmap

    hashmap to strmap

    hashmap was very mvp. into addition to transfering ownership in ext methods it allowed for mutabililty which shouldn't be needed in the context of an incoming request. instead we substitute with a type with read only interfaces that clones via Arc pointer ( since request.extentions require Sync ). This should be cheaper. a minimal set of interfaces is provided get(name), is_empty() and iter()

    opened by softprops 0
  • better handling of binary data

    better handling of binary data

    aws gateway requests and responses can have no body or a body that represented as text or binary

    https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-payload-encodings.html

    this wasn't previously represented well in the type system. events have an is_base64_encoded flag but thats not exposed directly to clients so body type representation would be more appropriate.

    This also fixes a previous problem where there was no way for handlers communicate this in responses.

    opened by softprops 0
  • expand documentation for multi-function applications

    expand documentation for multi-function applications

    most of the current documentation focuses on applications which produce a single function. many usecases exist for application that produce multiple functions. let's expand the docs to accommodate both because both are supported

    opened by softprops 0
Owner
Doug Tangren
rusting at sea
Doug Tangren
cargo-lambda a Cargo subcommand to help you work with AWS Lambda

cargo-lambda cargo-lambda is a Cargo subcommand to help you work with AWS Lambda. This subcommand compiles AWS Lambda functions natively and produces

David Calavera 184 Jan 5, 2023
cargo-lambda is a Cargo subcommand to help you work with AWS Lambda.

cargo-lambda cargo-lambda is a Cargo subcommand to help you work with AWS Lambda. The new subcommand creates a basic Rust package from a well defined

null 184 Jan 5, 2023
Rs.aws-login - A command line utility to simplify logging into AWS services.

aws-login A command line utility to simplify logging into AWS accounts and services. $ aws-login use ? Please select a profile to use: β€Ί ❯ dev-read

Kevin Herrera 11 Oct 30, 2022
A Rust runtime for AWS Lambda

Rust Runtime for AWS Lambda This package makes it easy to run AWS Lambda Functions written in Rust. This workspace includes multiple crates: lambda-ru

Amazon Web Services - Labs 2.4k Dec 29, 2022
A tool to run web applications on AWS Lambda without changing code.

AWS Lambda Adapter A tool to run web applications on AWS Lambda without changing code. How does it work? AWS Lambda Adapter supports AWS Lambda functi

AWS Samples 321 Jan 2, 2023
Aws-sdk-rust - AWS SDK for the Rust Programming Language

The AWS SDK for Rust This repo contains the new AWS SDK for Rust (the SDK) and its public roadmap. Please Note: The SDK is currently released as a dev

Amazon Web Services - Labs 2k Jan 3, 2023
A compatibility layer to smooth the transition between different versions of embedded-hal

Embedded HAL Compatibility Layer A compatibility layer to smooth the transition between different versions of embedded-hal (specifically 0.2.x and 1.0

Ryan 7 Sep 11, 2022
Rust Lambda Extension for any Runtime to preload SSM Parameters as πŸ” Secure Environment Variables!

?? Crypteia Rust Lambda Extension for any Runtime to preload SSM Parameters as Secure Environment Variables! Super fast and only performaned once duri

Custom Ink 34 Jan 7, 2023
The classic game Pong, written in lambda calculus, and a thin layer of Rust.

What? The good old game Pong, written in lambda calculus, and a thin layer of Rust. Why? I was bored. No, seriously, why? Everyone keeps saying that l

null 2 Aug 14, 2022
Examples of how to use Rust with Serverless Framework, Lambda, API Gateway v1 and v2, SQS, GraphQL, etc

Rust Serverless Examples All examples live in their own directories: project: there is nothing here, just a simple cargo new project_name with a custo

Fernando Daciuk 9 Dec 17, 2022
Serverless setup for activity pub (using lambda+dynamodb) in Rust

Serverless ActivityPub About This is an experiment to have free/cheaper activitypub instances running on AWS (making use of free tiers as much as poss

Conrad Ludgate 3 Dec 30, 2022
A lambda extension to hot reload parameters from SSM Parameter Store, Secrets Manager, DynamoDB, AppConfig

A lambda extension to hot reload parameters from SSM Parameter Store, Secrets Manager, DynamoDB, AppConfig

Jake Scott 7 Jun 12, 2022
A high-performance Lambda authorizer for API Gateway that can validate OIDC tokens

oidc-authorizer A high-performance token-based API Gateway authorizer Lambda that can validate OIDC-issued JWT tokens. ?? Use case This project provid

Luciano Mammino 4 Oct 30, 2023
Rust client for AWS Infinidash service.

AWS Infinidash - Fully featured Rust client Fully featured AWS Infinidash client for Rust applications. You can use the AWS Infinidash client to make

Rafael CarΓ­cio 15 Feb 12, 2022
Rusoto is an AWS SDK for Rust

Rusoto is an AWS SDK for Rust You may be looking for: An overview of Rusoto AWS services supported by Rusoto API documentation Getting help with Rusot

null 2.6k Jan 3, 2023
Cookiecutter templates for Serverless applications using AWS SAM and the Rust programming language.

Cookiecutter SAM template for Lambda functions in Rust This is a Cookiecutter template to create a serverless application based on the Serverless Appl

AWS Samples 24 Nov 11, 2022
Ref Arch: Serverless GraphQL in Rust on AWS

A Whole Hog Reference Architecture for an Apollo Federation-Ready, Serverless, Rust-Based GraphQL Microservice on AWS using Cloud Development Kit (CDK)

Michael Edelman 3 Jan 12, 2022
An opinionated Rust library for interacting with AWS DynamoDB single-table designs.

Modyne An opinionated library for interacting with AWS DynamoDB single-table designs. † Motive Modyne follows the precepts laid out for effective sing

Marcus Griep 14 Jun 8, 2023
Remote Secret Editor for AWS Secret Manager

Barberousse - Remote Secrets Editor About Usage Options Printing Editing Copying RoadMap 1.0 1.1 Future About A project aimed to avoid downloading sec

Mohamed Zenadi 18 Sep 28, 2021