I am trying to create an AWS Lambda function in Rust. Everything compiles and deploys fine but the invocation fails.
I have created a Minimum Reproducible Example (MRE) and included a Docker based build for repeatability. Keep in mind this is an MRE so you may see things which are not necessary for a basic hello world example, but they are integral to the original project that I am trying to troubleshoot.
Code
main.rs:
use hello::search::search;
use lambda_runtime::{service_fn, Error};
#[tokio::main]
async fn main() -> Result<(), Error> {
eprintln!("in main now!");
let handler = service_fn(search);
match lambda_runtime::run(handler).await {
Ok(()) => eprintln!("Lambda handler exited successfully!"),
Err(err) => eprintln!("Lambda handler failed: {}", err),
}
Ok(())
}
search.rs:
use lambda_runtime::{LambdaEvent, Error};
use serde_json::{json, Value};
pub async fn search(_: LambdaEvent<Option<String>>) -> Result<Value, Error> {
eprintln!("hello, logs!");
Ok(json!({
"statusCode": 200,
"headers": {
"Content-Type": "application/json"
},
"body": "{\"message\": \"hello, world!\"}"
}))
}
lib.rs:
pub mod search;
Configuration
template.yml:
AWSTemplateFormatVersion: 2010-09-09
Description: >-
my-api
Transform:
- AWS::Serverless-2016-10-31
Resources:
HelloRustFunction:
Type: AWS::Serverless::Function
Properties:
FunctionName: HelloRust
Handler: bootstrap.is.real.handler
Runtime: provided.al2
MemorySize: 512
CodeUri: .
Events:
Api:
Type: Api
Properties:
Path: /
Method: POST
RestApiId:
Ref: ApiGatewayRestApi
Metadata:
BuildMethod: makefile
ApiGatewayRestApi:
Type: AWS::Serverless::Api
Properties:
StageName: Prod
Outputs:
ApiGatewayUrl:
Value: !Sub "https://${ApiGatewayRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/"
Description: "API Gateway URL"
Cargo.toml:
[package]
name = "hello"
version = "0.1.0"
authors = ["root <root@localhost>"]
edition = "2018"
autobins = false
[[bin]]
name = "bootstrap"
path = "src/main.rs"
[dependencies]
lambda_runtime = "0.7.3"
serde = "1.0.80"
serde_derive = "1.0.80"
serde_json = "1.0.33"
http = "0.2.1"
regex = "1.7.1"
async-std = "1.12.0"
tokio = "1.25.0"
# https://stackoverflow.com/questions/74755175/unable-to-compile-rust-aws-lambda-using-rusoto
rusoto_core = {version = "0.48.0", features = ["rustls"], default-features = false}
rusoto_dynamodb = {version = "0.48.0", features = ["rustls"], default-features = false}
[profile.release]
opt-level = 'z' # Optimize for size
lto = true # Enable link-time optimization
codegen-units = 1 # Reduce number of codegen units to increase optimizations
panic = 'abort' # Abort on panic
strip = true # Strip symbols from binary*
[target.x86_64-unknown-linux-musl]
rustflags = ["-C", "target-feature=+crt-static"]
Makefile:
build-HelloRustFunction:
cargo build --release --target x86_64-unknown-linux-musl
cp ./target/x86_64-unknown-linux-musl/release/bootstrap $(ARTIFACTS_DIR)
Build & Deploy
Dockerfile:
# Docker build file, not used at runtime
FROM amazonlinux:2
RUN yum install -y openssl-devel gcc python3 python3-pip zip make tar gzip wget
RUN pip3 install awscli aws-sam-cli
# install musl
WORKDIR /root
RUN wget http://musl.libc.org/releases/musl-latest.tar.gz -O /tmp/musl-latest.tar.gz && \
tar zxvf /tmp/musl-latest.tar.gz && \
cd musl-* && \
./configure && \
make install
RUN ln -s /usr/local/musl/bin/musl-gcc /usr/bin
# install Rust
RUN curl https://sh.rustup.rs -sSf | sh -s -- -y
ENV PATH="/root/.cargo/bin:${PATH}"
RUN rustup target add x86_64-unknown-linux-musl
# force crates.io update
RUN cargo search rusoto_dynamodb
CMD ["/bin/bash"]
build_deploy.sh:
#!/bin/bash
docker build -t my-rust-project .
docker run -it -v "$(pwd)":/root/project -w /root/project -v ${HOME}/.aws/credentials:/root/.aws/credentials:ro my-rust-project sam build
docker run -it -v "$(pwd)":/root/project -w /root/project -v ${HOME}/.aws/credentials:/root/.aws/credentials:ro my-rust-project sam deploy
The problem
The build is successful and the AWS Lambda function is created.
When I invoke the function via curl
to the API Gateway endpoint, I get:
{"message": "Internal server error"}
Checking the Cloudwatch logs, I see in main now!
but not hello, logs!
.
It's as if the service_fn()
abstraction is doing something funky and never invokes my search()
function.
What could be causing this?