From 8510feae2fd70f7486e4f263bce7d499b9515fbb Mon Sep 17 00:00:00 2001 From: Maxime David Date: Tue, 7 Nov 2023 09:08:49 -0500 Subject: [PATCH 1/5] add multi functions example --- .../Cargo.toml | 13 ++++++ .../README.md | 22 +++++++++ .../consumer/Cargo.toml | 22 +++++++++ .../consumer/src/main.rs | 24 ++++++++++ .../pizza_lib/Cargo.toml | 7 +++ .../pizza_lib/src/lib.rs | 7 +++ .../producer/Cargo.toml | 25 +++++++++++ .../producer/src/main.rs | 45 +++++++++++++++++++ 8 files changed, 165 insertions(+) create mode 100644 examples/advanced-sqs-multiple-functions-shared-data/Cargo.toml create mode 100644 examples/advanced-sqs-multiple-functions-shared-data/README.md create mode 100644 examples/advanced-sqs-multiple-functions-shared-data/consumer/Cargo.toml create mode 100644 examples/advanced-sqs-multiple-functions-shared-data/consumer/src/main.rs create mode 100644 examples/advanced-sqs-multiple-functions-shared-data/pizza_lib/Cargo.toml create mode 100644 examples/advanced-sqs-multiple-functions-shared-data/pizza_lib/src/lib.rs create mode 100644 examples/advanced-sqs-multiple-functions-shared-data/producer/Cargo.toml create mode 100644 examples/advanced-sqs-multiple-functions-shared-data/producer/src/main.rs diff --git a/examples/advanced-sqs-multiple-functions-shared-data/Cargo.toml b/examples/advanced-sqs-multiple-functions-shared-data/Cargo.toml new file mode 100644 index 00000000..116ab8ef --- /dev/null +++ b/examples/advanced-sqs-multiple-functions-shared-data/Cargo.toml @@ -0,0 +1,13 @@ +[workspace] + +members = [ + "producer", + "consumer", + "pizza_lib", +] + +[profile.release] +opt-level = 'z' +lto = true +codegen-units = 1 +panic = 'abort' \ No newline at end of file diff --git a/examples/advanced-sqs-multiple-functions-shared-data/README.md b/examples/advanced-sqs-multiple-functions-shared-data/README.md new file mode 100644 index 00000000..21ce0015 --- /dev/null +++ b/examples/advanced-sqs-multiple-functions-shared-data/README.md @@ -0,0 +1,22 @@ +# AWS Lambda Function example + +## Build & Deploy + +1. Install [cargo-lambda](https://github.com/cargo-lambda/cargo-lambda#installation) +2. Build the function with `cargo lambda build --release` +3. Deploy the function to AWS Lambda with `cargo lambda deploy --iam-role YOUR_ROLE` + +## Build for ARM 64 + +Build the function with `cargo lambda build --release --arm64` + +## Add the SQS trigger to the consumer function + +You can use aws-cli to create an event source mapping: + +`aws lambda create-event-source-mapping \ +--function-name consumer \ +--region \ +--event-source-arn \ +--batch-size 1` + diff --git a/examples/advanced-sqs-multiple-functions-shared-data/consumer/Cargo.toml b/examples/advanced-sqs-multiple-functions-shared-data/consumer/Cargo.toml new file mode 100644 index 00000000..b2270bdd --- /dev/null +++ b/examples/advanced-sqs-multiple-functions-shared-data/consumer/Cargo.toml @@ -0,0 +1,22 @@ +[package] +name = "consumer" +version = "0.1.0" +edition = "2021" + + +[dependencies] +#tracing +tracing = "0.1.40" +tracing-subscriber = "0.3.17" + +#aws depdencies +aws-sdk-config = "0.35.0" +aws-sdk-sqs = "0.35.0" +aws_lambda_events = { version = "0.11.1", features = ["sqs"], default-features = false } + +#lambda runtime +lambda_runtime = "0.8.1" +tokio = { version = "1", features = ["macros"] } + +#shared lib +pizza_lib = { path = "../pizza_lib" } diff --git a/examples/advanced-sqs-multiple-functions-shared-data/consumer/src/main.rs b/examples/advanced-sqs-multiple-functions-shared-data/consumer/src/main.rs new file mode 100644 index 00000000..42290192 --- /dev/null +++ b/examples/advanced-sqs-multiple-functions-shared-data/consumer/src/main.rs @@ -0,0 +1,24 @@ +use aws_lambda_events::event::sqs::SqsEventObj; +use lambda_runtime::{service_fn, Error, LambdaEvent}; +use pizza_lib::Pizza; + +#[tokio::main] +async fn main() -> Result<(), Error> { + tracing_subscriber::fmt() + .with_max_level(tracing::Level::INFO) + .with_target(false) + .with_ansi(false) + .without_time() + .init(); + let func = service_fn(func); + lambda_runtime::run(func).await?; + Ok(()) +} + +async fn func(event: LambdaEvent>) -> Result<(), Error> { + for record in event.payload.records.iter() { + let pizza = &record.body; + println!("Pizza name: {} with toppings: {:?}", pizza.name, pizza.toppings); + } + Ok(()) +} diff --git a/examples/advanced-sqs-multiple-functions-shared-data/pizza_lib/Cargo.toml b/examples/advanced-sqs-multiple-functions-shared-data/pizza_lib/Cargo.toml new file mode 100644 index 00000000..76631bbd --- /dev/null +++ b/examples/advanced-sqs-multiple-functions-shared-data/pizza_lib/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "pizza_lib" +version = "0.1.0" +edition = "2021" + +[dependencies] +serde = { version = "1.0.191", features = ["derive"] } diff --git a/examples/advanced-sqs-multiple-functions-shared-data/pizza_lib/src/lib.rs b/examples/advanced-sqs-multiple-functions-shared-data/pizza_lib/src/lib.rs new file mode 100644 index 00000000..638fa762 --- /dev/null +++ b/examples/advanced-sqs-multiple-functions-shared-data/pizza_lib/src/lib.rs @@ -0,0 +1,7 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize)] +pub struct Pizza { + pub name: String, + pub toppings: Vec, +} diff --git a/examples/advanced-sqs-multiple-functions-shared-data/producer/Cargo.toml b/examples/advanced-sqs-multiple-functions-shared-data/producer/Cargo.toml new file mode 100644 index 00000000..557ac6e5 --- /dev/null +++ b/examples/advanced-sqs-multiple-functions-shared-data/producer/Cargo.toml @@ -0,0 +1,25 @@ +[package] +name = "producer" +version = "0.1.0" +edition = "2021" + +[package.metadata.lambda.deploy] +env = { "QUEUE_URL" = "https://changeMe" } + +[dependencies] +#tracing +tracing = "0.1.40" +tracing-subscriber = "0.3.17" + +#aws dependencies +aws-config = "0.57.1" +aws-sdk-config = "0.35.0" +aws-sdk-sqs = "0.35.0" + +#lambda runtime +lambda_runtime = "0.8.1" +serde_json = "1.0.108" +tokio = { version = "1", features = ["macros"] } + +#shared lib +pizza_lib = { path = "../pizza_lib" } \ No newline at end of file diff --git a/examples/advanced-sqs-multiple-functions-shared-data/producer/src/main.rs b/examples/advanced-sqs-multiple-functions-shared-data/producer/src/main.rs new file mode 100644 index 00000000..5d8fa386 --- /dev/null +++ b/examples/advanced-sqs-multiple-functions-shared-data/producer/src/main.rs @@ -0,0 +1,45 @@ +use lambda_runtime::{service_fn, Error, LambdaEvent}; +use pizza_lib::Pizza; +use serde_json::{json, Value}; + +#[tokio::main] +async fn main() -> Result<(), Error> { + tracing_subscriber::fmt() + .with_max_level(tracing::Level::INFO) + .with_target(false) + .with_ansi(false) + .without_time() + .init(); + let func = service_fn(func); + lambda_runtime::run(func).await?; + Ok(()) +} + +async fn func(_: LambdaEvent) -> Result<(), Error> { + // read the queue url from the environment + let queue_url = std::env::var("QUEUE_URL").expect("could not read QUEUE_URL"); + + // let's create our pizza + let message = Pizza { + name: "margherita".to_string(), + toppings: vec![ + "San Marzano Tomatoes".to_string(), + "Fresh Mozzarella".to_string(), + "Basil".to_string(), + ], + }; + + // create our SQS client + let config = aws_config::from_env().load().await; + + // send our message to SQS + let client = aws_sdk_sqs::Client::new(&config); + client + .send_message() + .queue_url(queue_url) + .message_body(json!(message).to_string()) + .send() + .await?; + + Ok(()) +} From 4a20364006cb930eda571800fc7b5bfaef50bb08 Mon Sep 17 00:00:00 2001 From: Maxime David Date: Tue, 7 Nov 2023 11:23:58 -0500 Subject: [PATCH 2/5] update Readme --- .../README.md | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/examples/advanced-sqs-multiple-functions-shared-data/README.md b/examples/advanced-sqs-multiple-functions-shared-data/README.md index 21ce0015..83136b9b 100644 --- a/examples/advanced-sqs-multiple-functions-shared-data/README.md +++ b/examples/advanced-sqs-multiple-functions-shared-data/README.md @@ -4,7 +4,12 @@ 1. Install [cargo-lambda](https://github.com/cargo-lambda/cargo-lambda#installation) 2. Build the function with `cargo lambda build --release` -3. Deploy the function to AWS Lambda with `cargo lambda deploy --iam-role YOUR_ROLE` +4. Make sure to edit the QUEUE_URL env variable in producer/Cargo.toml +3. Deploy boths functions to AWS Lambda with + +`cargo lambda deploy consumer --iam-role YOUR_ROLE` + +`cargo lambda deploy producer --iam-role YOUR_ROLE` ## Build for ARM 64 @@ -14,9 +19,10 @@ Build the function with `cargo lambda build --release --arm64` You can use aws-cli to create an event source mapping: -`aws lambda create-event-source-mapping \ +```bash +aws lambda create-event-source-mapping \ --function-name consumer \ --region \ --event-source-arn \ ---batch-size 1` - +--batch-size 1 +``` \ No newline at end of file From 50a063d1866c928e7741b42415611b20d72a640c Mon Sep 17 00:00:00 2001 From: Maxime David Date: Tue, 7 Nov 2023 13:19:54 -0500 Subject: [PATCH 3/5] pr comment --- .../producer/src/main.rs | 40 +++++++++++++------ 1 file changed, 28 insertions(+), 12 deletions(-) diff --git a/examples/advanced-sqs-multiple-functions-shared-data/producer/src/main.rs b/examples/advanced-sqs-multiple-functions-shared-data/producer/src/main.rs index 5d8fa386..9dc0eb7b 100644 --- a/examples/advanced-sqs-multiple-functions-shared-data/producer/src/main.rs +++ b/examples/advanced-sqs-multiple-functions-shared-data/producer/src/main.rs @@ -2,6 +2,17 @@ use lambda_runtime::{service_fn, Error, LambdaEvent}; use pizza_lib::Pizza; use serde_json::{json, Value}; +struct SQSManager { + client: aws_sdk_sqs::Client, + queue_url: String, +} + +impl SQSManager { + fn new(client: aws_sdk_sqs::Client, queue_url: String) -> Self { + Self { client, queue_url } + } +} + #[tokio::main] async fn main() -> Result<(), Error> { tracing_subscriber::fmt() @@ -10,15 +21,24 @@ async fn main() -> Result<(), Error> { .with_ansi(false) .without_time() .init(); - let func = service_fn(func); - lambda_runtime::run(func).await?; - Ok(()) -} -async fn func(_: LambdaEvent) -> Result<(), Error> { // read the queue url from the environment let queue_url = std::env::var("QUEUE_URL").expect("could not read QUEUE_URL"); + // build the config from environment variables (fed by AWS Lambda) + let config = aws_config::from_env().load().await; + // create our SQS Manager + let sqs_manager = SQSManager::new(aws_sdk_sqs::Client::new(&config), queue_url); + let sqs_manager_ref = &sqs_manager; + // no need to create a SQS Client for each incoming request, let's use a shared state + let handler_func_closure = |event: LambdaEvent| async move { + Result::<(), Error>::Ok(process_event(event, sqs_manager_ref).await?) + }; + lambda_runtime::run(service_fn(handler_func_closure)).await?; + Ok(()) +} + +async fn process_event(_: LambdaEvent, sqs_manager: &SQSManager) -> Result<(), Error> { // let's create our pizza let message = Pizza { name: "margherita".to_string(), @@ -28,15 +48,11 @@ async fn func(_: LambdaEvent) -> Result<(), Error> { "Basil".to_string(), ], }; - - // create our SQS client - let config = aws_config::from_env().load().await; - // send our message to SQS - let client = aws_sdk_sqs::Client::new(&config); - client + sqs_manager + .client .send_message() - .queue_url(queue_url) + .queue_url(&sqs_manager.queue_url) .message_body(json!(message).to_string()) .send() .await?; From b66da224690b02fd4a3840241451e4be6a39ef35 Mon Sep 17 00:00:00 2001 From: Maxime David Date: Tue, 7 Nov 2023 13:20:08 -0500 Subject: [PATCH 4/5] pr comments --- .../consumer/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/advanced-sqs-multiple-functions-shared-data/consumer/Cargo.toml b/examples/advanced-sqs-multiple-functions-shared-data/consumer/Cargo.toml index b2270bdd..8555a073 100644 --- a/examples/advanced-sqs-multiple-functions-shared-data/consumer/Cargo.toml +++ b/examples/advanced-sqs-multiple-functions-shared-data/consumer/Cargo.toml @@ -9,7 +9,7 @@ edition = "2021" tracing = "0.1.40" tracing-subscriber = "0.3.17" -#aws depdencies +#aws dependencies aws-sdk-config = "0.35.0" aws-sdk-sqs = "0.35.0" aws_lambda_events = { version = "0.11.1", features = ["sqs"], default-features = false } From 4f36363f389ad275e7480fcc1b4f0965d6f61a65 Mon Sep 17 00:00:00 2001 From: Maxime David Date: Tue, 7 Nov 2023 13:20:51 -0500 Subject: [PATCH 5/5] run clippy --- .../producer/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/advanced-sqs-multiple-functions-shared-data/producer/src/main.rs b/examples/advanced-sqs-multiple-functions-shared-data/producer/src/main.rs index 9dc0eb7b..2cc2541b 100644 --- a/examples/advanced-sqs-multiple-functions-shared-data/producer/src/main.rs +++ b/examples/advanced-sqs-multiple-functions-shared-data/producer/src/main.rs @@ -32,7 +32,7 @@ async fn main() -> Result<(), Error> { // no need to create a SQS Client for each incoming request, let's use a shared state let handler_func_closure = |event: LambdaEvent| async move { - Result::<(), Error>::Ok(process_event(event, sqs_manager_ref).await?) + process_event(event, sqs_manager_ref).await }; lambda_runtime::run(service_fn(handler_func_closure)).await?; Ok(())