#aws-lambda #run-time #lambda #aws #amazon-web-services #event-handling

rtlambda

AWS Lambda 的 Rust 运行时以及创建自定义运行时的库

1 个不稳定版本

0.0.1 2022 年 5 月 22 日

#45#event-handling

MIT/Apache

47KB
744

rtlambda

rtlambda 是一个 AWS Lambda 的 Rust 运行时以及创建自定义运行时的库。

rtlambda 默认的运行时实现允许您为 AWS Lambda 编写本机 Rust 事件处理器。

您的处理器代码将与运行时一起编译成单个可执行文件,然后部署到 Lambda 服务。

rtlambda 将依赖和复杂性保持在最低,并且不依赖于 tokio。编写 rtlambda 函数既简单又容易。

使用方法

要开始,您可以修改 echo-server 示例

rtlambdaserde 作为依赖项添加到您的 Cargo.toml 文件中

[dependencies]
rtlambda = "0.0.1"
serde = { version = "1", features = ["derive"] }

并在您的 main.rs 文件中

use rtlambda::prelude::*;
use serde::Serialize;

// Import the [`default_runtime`] macro from rtlambda.
#[macro_use] extern crate rtlambda;

// Create a struct representing the lambda's response, and derive the [`serde::Serialize`] trait.
#[derive(Serialize, Clone)]
struct EchoMessage {
    msg: String,
    req_id: String,
}

// Define output and error types for berevity.
// The Output type must implement [`serde::Serialize`]
type OUT = EchoMessage;
// The error type must implement the `Display` trait
type ERR = String;

// Implement an initialization function.
// The initialization function returns a Result with the Ok type resolving to a dynamically allocated
// closure that accepts the Event from Lambda (as an optional string) and the context object.
// The closure itself returns a Result with the Ok and Err types being the previously defined `OUT` and `ERR` types respectively.
// The initialization function may fail (e.g if a db connection was not succesfully opened, etc..) and in that case
// the function should return an Err variant of the same `ERR` type defined for the event handler.
fn initialize() -> Result<
    Box<dyn Fn(Option<&str>, RefLambdaContext<LambdaRuntimeEnv, UreqResponse>) -> Result<OUT, ERR>>,
    ERR,
> {
    // Your one-time initialization logic goes here:

    //

    // Return the event handler closure
    return Ok(Box::new(move |event, context| {
        // Get the aws request id
        let req_id = context.aws_request_id().unwrap();

        // Unwrap the event string 
        let event = match event {
            Some(v) => v,
            None => {
                return Err(format!(
                    "AWS should not permit empty events. Something strange must've happened."
                ))
            }
        };
        
        if event == "\"\"" {
            return Err(format!("Empty input, nothing to echo."));
        }

        // rtlambda leaves use-case specific concerns such as event JSON deserialization to the handler.
        // In this example we do not deserialize the event. Use serde_json or any other library to perform deserialization if needed.

        // Echo the event back as a string.
        Ok(EchoMessage {
            msg: format!("ECHO: {}", event),
            req_id: req_id.to_string(),
        })

    }));
}

fn main() {
    // Create a runtime instance and run its loop.
    // This is the equivalent of:
    // let mut runtime =  DefaultRuntime::<UreqResponse, UreqTransport, LambdaRuntimeEnv, OUT, ERR>::new(LAMBDA_VER, initialize);
    let mut runtime = default_runtime!(OUT, ERR, LAMBDA_VER, initialize);

    runtime.run();
}

它是如何工作的

您的 main 函数代码创建并运行运行时,该运行时在接收到事件时调用您的处理器,并在出错时处理错误。

典型的设置包括

  • 创建一个新的二进制包,并在您的 Cargo.toml 文件中将 rtlambda 作为依赖项包括在内。
  • main.rs 文件中导入预导入 - rtlambda::prelude::*
  • 编写一个初始化函数,该函数包含一次性初始化代码并返回一个闭包 - 包含事件处理逻辑(Lambda 的业务逻辑)。
  • 在您的 main 函数中,创建一个新的 DefaultRuntime,传递 Lambda API 版本和指向您的初始化函数的指针。
  • 在运行时实例上调用 run() 方法以启动运行时。

作为一个框架

rtlambda 的 API 利用泛型特性 - 以及它们的类型参数上的界限 - 来定义其接口。

这种设计最小化了动态派遣调用,同时允许用户

  • 定义他们自己的输出和错误类型。
  • 选择他们的 HTTP 客户端实现。
  • 实现他们自己的内部运行时关注点版本,例如运行时逻辑、环境变量处理和上下文构建。

每个特性都提供了一个默认类型实现。例如,默认的 HTTP 后端基于 ureq

大多数用户应该可以使用默认实现,只需定义它们的输出和错误类型。输出类型目前应实现serde::Serialize特质。错误类型应实现std::fmt::Display

构建和部署

rtlambda被设计为构建成一个包含您的函数代码和运行时本身的单一可执行文件(在AWS术语中,运行时“嵌入在函数部署包中”)。

AWS目前允许您在基于x86aarch64的机器上部署您的函数,这些机器上运行的是Amazon Linux 2操作系统或旧的Amazon Linux。

由于Rust是一种编译型语言,因此需要在您计划部署到的相同环境中构建您的项目(或进行交叉编译)。

构建您的代码有两种简单的方法:使用Docker或启动一个与目标环境匹配的EC2虚拟机。

使用Docker

对于Amazon Linux 2,您可以按照以下步骤操作

  1. 克隆https://github.com/guyo13/amazon_linux_rust_docker.git
  2. 切换到x86aarch64目录,并运行docker build .
  3. 运行一个包含构建镜像的容器,并将您的crate根目录挂载到容器的/opt/src目录 - 通过在docker run命令中添加-v /path/to/crate:/opt/src参数来实现。
  4. 连接到容器并执行cargo build --release
  5. 对于aarch64构建为了最好地利用AWS Graviton2 CPU,在构建之前,在容器内部运行以下命令:export RUSTFLAGS="-C target-cpu=neoverse-n1 -C target-feature=+lse,+outline-atomics"

如果您的宿主架构(例如x86笔记本电脑/mac)与您的目标架构相匹配,此方法似乎可行。在Docker for Mac上使用rustc 1.60在仿真容器中构建失败。

使用虚拟机

  • EC2上创建一个与您的目标平台(架构和操作系统)相匹配的虚拟机。
  • 使用rustup-init(说明)安装Rust工具链。
  • 将您的crate克隆到构建虚拟机中,并在虚拟机上重复上述步骤4-5(这次没有容器)。

部署

在Docker或虚拟机上编译完您的应用程序后,将可执行二进制文件复制到名为bootstrap的文件中,并将其压缩成function.zip存档。

使用AWS Lambda仪表板或aws cli创建一个函数,确保平台设置(CPU架构和操作系统)与您的编译目标相匹配。使用AWS支持的方法之一将您的function.zip存档部署到新创建的函数。

许可证

rtlambda双许可下为MIT或Apache-2.0。有关详细信息,请参阅所包含的许可证文件。

依赖项

~2–2.8MB
~78K SLoC