Skip to content

Commit 2a82ba7

Browse files
authored
Add an advanced SQS multiple functions with shared data example (#720)
* add multi functions example * update Readme * pr comment * pr comments * run clippy
1 parent c565173 commit 2a82ba7

File tree

8 files changed

+187
-0
lines changed

8 files changed

+187
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
[workspace]
2+
3+
members = [
4+
"producer",
5+
"consumer",
6+
"pizza_lib",
7+
]
8+
9+
[profile.release]
10+
opt-level = 'z'
11+
lto = true
12+
codegen-units = 1
13+
panic = 'abort'
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# AWS Lambda Function example
2+
3+
## Build & Deploy
4+
5+
1. Install [cargo-lambda](https://github.com/cargo-lambda/cargo-lambda#installation)
6+
2. Build the function with `cargo lambda build --release`
7+
4. Make sure to edit the QUEUE_URL env variable in producer/Cargo.toml
8+
3. Deploy boths functions to AWS Lambda with
9+
10+
`cargo lambda deploy consumer --iam-role YOUR_ROLE`
11+
12+
`cargo lambda deploy producer --iam-role YOUR_ROLE`
13+
14+
## Build for ARM 64
15+
16+
Build the function with `cargo lambda build --release --arm64`
17+
18+
## Add the SQS trigger to the consumer function
19+
20+
You can use aws-cli to create an event source mapping:
21+
22+
```bash
23+
aws lambda create-event-source-mapping \
24+
--function-name consumer \
25+
--region <region> \
26+
--event-source-arn <your-SQS-queue-ARN> \
27+
--batch-size 1
28+
```
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
[package]
2+
name = "consumer"
3+
version = "0.1.0"
4+
edition = "2021"
5+
6+
7+
[dependencies]
8+
#tracing
9+
tracing = "0.1.40"
10+
tracing-subscriber = "0.3.17"
11+
12+
#aws dependencies
13+
aws-sdk-config = "0.35.0"
14+
aws-sdk-sqs = "0.35.0"
15+
aws_lambda_events = { version = "0.11.1", features = ["sqs"], default-features = false }
16+
17+
#lambda runtime
18+
lambda_runtime = "0.8.1"
19+
tokio = { version = "1", features = ["macros"] }
20+
21+
#shared lib
22+
pizza_lib = { path = "../pizza_lib" }
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
use aws_lambda_events::event::sqs::SqsEventObj;
2+
use lambda_runtime::{service_fn, Error, LambdaEvent};
3+
use pizza_lib::Pizza;
4+
5+
#[tokio::main]
6+
async fn main() -> Result<(), Error> {
7+
tracing_subscriber::fmt()
8+
.with_max_level(tracing::Level::INFO)
9+
.with_target(false)
10+
.with_ansi(false)
11+
.without_time()
12+
.init();
13+
let func = service_fn(func);
14+
lambda_runtime::run(func).await?;
15+
Ok(())
16+
}
17+
18+
async fn func(event: LambdaEvent<SqsEventObj<Pizza>>) -> Result<(), Error> {
19+
for record in event.payload.records.iter() {
20+
let pizza = &record.body;
21+
println!("Pizza name: {} with toppings: {:?}", pizza.name, pizza.toppings);
22+
}
23+
Ok(())
24+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
[package]
2+
name = "pizza_lib"
3+
version = "0.1.0"
4+
edition = "2021"
5+
6+
[dependencies]
7+
serde = { version = "1.0.191", features = ["derive"] }
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
use serde::{Deserialize, Serialize};
2+
3+
#[derive(Serialize, Deserialize)]
4+
pub struct Pizza {
5+
pub name: String,
6+
pub toppings: Vec<String>,
7+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
[package]
2+
name = "producer"
3+
version = "0.1.0"
4+
edition = "2021"
5+
6+
[package.metadata.lambda.deploy]
7+
env = { "QUEUE_URL" = "https://changeMe" }
8+
9+
[dependencies]
10+
#tracing
11+
tracing = "0.1.40"
12+
tracing-subscriber = "0.3.17"
13+
14+
#aws dependencies
15+
aws-config = "0.57.1"
16+
aws-sdk-config = "0.35.0"
17+
aws-sdk-sqs = "0.35.0"
18+
19+
#lambda runtime
20+
lambda_runtime = "0.8.1"
21+
serde_json = "1.0.108"
22+
tokio = { version = "1", features = ["macros"] }
23+
24+
#shared lib
25+
pizza_lib = { path = "../pizza_lib" }
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
use lambda_runtime::{service_fn, Error, LambdaEvent};
2+
use pizza_lib::Pizza;
3+
use serde_json::{json, Value};
4+
5+
struct SQSManager {
6+
client: aws_sdk_sqs::Client,
7+
queue_url: String,
8+
}
9+
10+
impl SQSManager {
11+
fn new(client: aws_sdk_sqs::Client, queue_url: String) -> Self {
12+
Self { client, queue_url }
13+
}
14+
}
15+
16+
#[tokio::main]
17+
async fn main() -> Result<(), Error> {
18+
tracing_subscriber::fmt()
19+
.with_max_level(tracing::Level::INFO)
20+
.with_target(false)
21+
.with_ansi(false)
22+
.without_time()
23+
.init();
24+
25+
// read the queue url from the environment
26+
let queue_url = std::env::var("QUEUE_URL").expect("could not read QUEUE_URL");
27+
// build the config from environment variables (fed by AWS Lambda)
28+
let config = aws_config::from_env().load().await;
29+
// create our SQS Manager
30+
let sqs_manager = SQSManager::new(aws_sdk_sqs::Client::new(&config), queue_url);
31+
let sqs_manager_ref = &sqs_manager;
32+
33+
// no need to create a SQS Client for each incoming request, let's use a shared state
34+
let handler_func_closure = |event: LambdaEvent<Value>| async move {
35+
process_event(event, sqs_manager_ref).await
36+
};
37+
lambda_runtime::run(service_fn(handler_func_closure)).await?;
38+
Ok(())
39+
}
40+
41+
async fn process_event(_: LambdaEvent<Value>, sqs_manager: &SQSManager) -> Result<(), Error> {
42+
// let's create our pizza
43+
let message = Pizza {
44+
name: "margherita".to_string(),
45+
toppings: vec![
46+
"San Marzano Tomatoes".to_string(),
47+
"Fresh Mozzarella".to_string(),
48+
"Basil".to_string(),
49+
],
50+
};
51+
// send our message to SQS
52+
sqs_manager
53+
.client
54+
.send_message()
55+
.queue_url(&sqs_manager.queue_url)
56+
.message_body(json!(message).to_string())
57+
.send()
58+
.await?;
59+
60+
Ok(())
61+
}

0 commit comments

Comments
 (0)