-
Notifications
You must be signed in to change notification settings - Fork 361
Add an advanced SQS multiple functions with shared data example #720
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
[workspace] | ||
|
||
members = [ | ||
"producer", | ||
"consumer", | ||
"pizza_lib", | ||
] | ||
|
||
[profile.release] | ||
opt-level = 'z' | ||
lto = true | ||
codegen-units = 1 | ||
panic = 'abort' |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
# 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` | ||
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 | ||
|
||
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: | ||
|
||
```bash | ||
aws lambda create-event-source-mapping \ | ||
--function-name consumer \ | ||
--region <region> \ | ||
--event-source-arn <your-SQS-queue-ARN> \ | ||
--batch-size 1 | ||
``` |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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" } |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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<SqsEventObj<Pizza>>) -> Result<(), Error> { | ||
for record in event.payload.records.iter() { | ||
let pizza = &record.body; | ||
println!("Pizza name: {} with toppings: {:?}", pizza.name, pizza.toppings); | ||
} | ||
Ok(()) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
[package] | ||
name = "pizza_lib" | ||
version = "0.1.0" | ||
edition = "2021" | ||
|
||
[dependencies] | ||
serde = { version = "1.0.191", features = ["derive"] } |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
use serde::{Deserialize, Serialize}; | ||
|
||
#[derive(Serialize, Deserialize)] | ||
pub struct Pizza { | ||
pub name: String, | ||
pub toppings: Vec<String>, | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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"] } | ||
Comment on lines
+9
to
+22
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. to fully show the possibilities of the workspace model, you might consider putting these dependencies that are shared between producer and consumer in workspace dependencies. https://doc.rust-lang.org/nightly/cargo/reference/workspaces.html#the-dependencies-table There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yeah, I just wanted to show how to share a struct, so I feel that this change might confuse the user? WDYT? I don't have a strong opinion here so let me know if you want me to make that change :) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. i don't feel strongly about it |
||
|
||
#shared lib | ||
pizza_lib = { path = "../pizza_lib" } |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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<Value>) -> 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); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. np: comments are a bit mis-aligned here. you say "create our SQS client" when you're just creating the config, then say "send our message" when you create the SQS client. actually, do you think it makes sense to model the SQS client as shared state here? that'd be best practice. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. you're totally right, I've moved it to a shared state! |
||
client | ||
.send_message() | ||
.queue_url(queue_url) | ||
.message_body(json!(message).to_string()) | ||
.send() | ||
.await?; | ||
|
||
Ok(()) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: typo
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thanks! fixed