Luciano Mammino PRO
Cloud developer, entrepreneur, fighter, butterfly maker! #nodejs #javascript - Author of https://www.nodejsdesignpatterns.com , Founder of https://fullstackbulletin.com
Luciano Mammino (@loige)
2024-10-23
๐ I'm Luciano (๐ฎ๐น๐๐๐ค)
๐จโ๐ป Senior Architect @ fourTheorem
๐ Co-Author of Node.js Design Patterns ๐
Let's connect!
๐ I'm Luciano (๐ฎ๐น๐๐๐ค)
๐จโ๐ป Senior Architect @ fourTheorem
๐ Co-Author of Crafting Lambda Functions in Rust ๐
Let's connect!
Early-access available at
50% discount! ๐ค
โ๏ธ Reach out to us at hello@fourTheorem.com
๐ We are always looking for talent: fth.link/careers
We can help with:
Cloud Migrations
Training & Cloud enablement
Building high-performance serverless applications
Cutting cloud costs
๐ loige
๐ loige
A way of running applications in the cloud
Of course, there are servers... we just don't have to manage them
We pay (only) for what we use
Small units of compute (functions), triggered by events
๐ loige
More focus on the business logic (generally)
Increased team agility (mostly)
Automatic scalability (sorta)
Not a universal solution, but it can work well in many situations!
๐ loige
Serverless FaaS offering in AWS
Can be triggered by different kinds of events
๐ loige
... so again, it's not a silver bullet for all your compute problems! ๐ซ
๐ loige
Cost = Allocated Memory ๐ time
๐ loige
๐ฐ ๐๏ธโโ๏ธ โฑ๏ธ
Cost = Allocated Memory ๐ time
๐ loige
๐ฐ ๐๏ธโโ๏ธ โฑ๏ธ
๐ loige
๐ loige
๐ loige
๐ loige
๐ loige
RUST?!
๐ loige
RUST?!
๐ loige
EASY PEASY... we just need a custom runtime! ๐ค
๐ loige
๐ loige
Runtime
Handler (logic)
๐ loige
Runtime
Handler (logic)
Poll for events
๐ loige
Runtime
Handler (logic)
Poll for events
event (JSON)
๐ loige
Runtime
Handler (logic)
Poll for events
event (JSON)
execute
๐ loige
Runtime
Handler (logic)
Poll for events
event (JSON)
execute
response or
error
๐ loige
Runtime
Handler (logic)
Poll for events
event (JSON)
execute
response or
error
response (JSON)
or error
๐ loige
๐ loige
๐ loige
๐ loige
Load the handler code
Infinite loop
๐ loige
๐ loige
๐ loige
๐ loige
๐ loige
๐ loige
๐ loige
๐ loige
# Docker
docker version
# (...)
# Rust
cargo --version
# -> cargo 1.82.0 (8f40fc59f 2024-08-21)
# Zig (for cross-compiling lambda binaries)
zig version
# -> 0.13.0
# AWS
aws --version
# -> aws-cli/2.17.0 Python/3.11.8 Darwin/23.6.0 exe/x86_64
# AWS login
# you might need to run extra commands to get temporary credentials if you use AWS organizations
# details on how to configure your CLI here: https://docs.aws.amazon.com/cli/latest/userguide/getting-started-quickstart.html
aws sts get-caller-identity
# ->
# {
# "UserId": "AROATBJTMBXWT2ZAVHYOW:luciano",
# "Account": "208950529517",
# "Arn": "arn:aws:sts::208950529517:assumed-role/AWSReservedSSO_AdministratorAccess_d0f4d19d5ba1f39f/luciano"
# }
# Cargo Lambda
cargo lambda --version
# -> cargo-lambda 1.4.0 (e3bd536 2024-09-07Z)
# SAM
sam --version
# -> SAM CLI, version 1.126.0
๐ loige
cargo lambda new itsalive
๐ loige
๐ loige
๐ loige
// src/main.rs
use aws_lambda_events::event::eventbridge::EventBridgeEvent;
use lambda_runtime::{run, service_fn, tracing, Error, LambdaEvent};
async fn function_handler(event: LambdaEvent<EventBridgeEvent>)
-> Result<(), Error> {
dbg!(event);
Ok(())
}
#[tokio::main]
async fn main() -> Result<(), Error> {
tracing::init_default_subscriber();
run(service_fn(function_handler)).await
}
๐ loige
{
"version": "0",
"id": "53dc4d37-cffa-4f76-80c9-8b7d4a4d2eaa",
"detail-type": "Scheduled Event",
"source": "aws.events",
"account": "123456789012",
"time": "2015-10-08T16:53:06Z",
"region": "us-east-1",
"resources": [
"arn:aws:events:us-east-1:123456789012:rule/my-scheduled-rule"
],
"detail": {}
}
Sample event
๐ loige
cargo lambda watch
cargo lambda invoke --data-file "events/eventbridge.json"
Or use one of the official example events:
cargo lambda invoke --data-example eventbridge-schedule
๐ loige
๐ loige
cargo lambda build --arm64 --release
cargo lambda release
๐ loige
๐ loige
๐ loige
# template.yml
AWSTemplateFormatVersion: 2010-09-09
Transform: AWS::Serverless-2016-10-31
Resources:
HealthCheckLambda:
Type: AWS::Serverless::Function
Metadata:
BuildMethod: rust-cargolambda
Properties:
CodeUri: .
Handler: bootstrap
Runtime: provided.al2023
Architectures:
- arm64
MemorySize: 256
Timeout: 70
Events:
ScheduledExecution:
Type: Schedule
Properties:
Schedule: rate(30 minutes)
๐ loige
๐ loige
sam validate --lint \
&& sam build --beta-features \
&& sam deploy --guided
๐ loige
๐ loige
๐ loige
๐ loige
๐ loige
๐ loige
๐ loige
๐ loige
๐ loige
cargo add reqwest \
--no-default-features \
--features "rustls-tls,http2"
๐ loige
// src/main.rs
async fn function_handler(_event: LambdaEvent<EventBridgeEvent<Value>>) -> Result<(), Error> {
let start = Instant::now();
let resp = reqwest::get("https://loige.co").await;
let duration = start.elapsed();
match resp {
Ok(resp) => {
let status = resp.status().as_u16();
let success = resp.status().is_success();
dbg!(status);
dbg!(success);
dbg!(duration);
}
Err(e) => {
eprintln!("The request failed: {}", e);
}
}
Ok(())
}
๐ loige
# template.yml
Resources:
# ...
HealthChecksTable:
Type: AWS::DynamoDB::Table
DeletionPolicy: Delete
UpdateReplacePolicy: Delete
Properties:
BillingMode: PAY_PER_REQUEST
KeySchema:
- AttributeName: "Id"
KeyType: "HASH"
- AttributeName: "Timestamp"
KeyType: "RANGE"
AttributeDefinitions:
- AttributeName: "Id"
AttributeType: "S"
- AttributeName: "Timestamp"
AttributeType: "S"
๐ loige
# template.yml
Resources:
# ...
HealthCheckLambda:
Type: AWS::Serverless::Function
# ...
Properties:
# ...
Environment:
Variables:
TABLE_NAME: !Ref HealthChecksTable
Policies:
- DynamoDBWritePolicy:
TableName: !Ref HealthChecksTable
๐ loige
cargo add aws-config aws-sdk-dynamodb
๐ loige
let table_name = env::var("TABLE_NAME").expect("TABLE_NAME not set");
let config = aws_config::defaults(BehaviorVersion::latest())
.load()
.await;
let dynamodb_client = aws_sdk_dynamodb::Client::new(&config);
let timestamp = event
.payload
.time
.unwrap()
.format("%+")
.to_string();
let mut item = HashMap::new();
item.insert(
"Id".to_string(),
AttributeValue::S(format!("https://loige.co#{}", timestamp)),
);
item.insert("Timestamp".to_string(), AttributeValue::S(timestamp));
๐ loige
let success = match resp {
Ok(resp) => {
let status = resp.status().as_u16();
item.insert("Status".to_string(), AttributeValue::N(status.to_string()));
item.insert(
"Duration".to_string(),
AttributeValue::N(duration.as_millis().to_string()),
);
resp.status().is_success()
}
Err(e) => {
item.insert("Error".to_string(), AttributeValue::S(e.to_string()));
false
}
};
item.insert("Success".to_string(), AttributeValue::Bool(success));
๐ loige
let insert_result = dynamodb_client
.put_item()
.table_name(table_name.as_str())
.set_item(Some(item))
.send()
.await?;
tracing::info!("Insert result: {:?}", insert_result);
๐ loige
sam validate --lint \
&& sam build --beta-features \
&& sam deploy
๐ loige
๐ loige
๐ loige
๐ loige
sam delete
๐ loige
Check out the repo for a better and more complete implementation!
๐ loige
๐ loige
๐ loige
๐ loige
๐ loige
Early-access available at
50% discount! ๐ค
THANKS!
Grab these slides!
๐ loige
Early-access available at
50% discount! ๐ค
By Luciano Mammino
Take your serverless functions to new heights by pairing AWS Lambda with the high-performance powers of Rust. In this hands-on workshop, you'll discover how to write optimized, scalable, and maintainable serverless code using Rust as your runtime. Learn: Why Rust + Lambda is a match made in heaven The tooling ecosystem for seamless development Best practices for handling events and responses Integration with Infrastructure as Code tools By the end of this session, you'll be equipped to harness Rust's performance benefits and revolutionize your serverless workflows. Prerequisites: basic AWS & Lambda knowledge, some Rust experience (or a willingness to learn).
Cloud developer, entrepreneur, fighter, butterfly maker! #nodejs #javascript - Author of https://www.nodejsdesignpatterns.com , Founder of https://fullstackbulletin.com