Skip to content

Commit cc239ea

Browse files
authored
Relax blanket implementation of Diagnostic (#897)
Instead of implementing Diagnostic for everything that implements Display, implement the trait only for a few well known types. This gives people more flexibility to implement Diagnostic. Signed-off-by: David Calavera <david.calavera@gmail.com>
1 parent 92cdd74 commit cc239ea

File tree

17 files changed

+251
-110
lines changed

17 files changed

+251
-110
lines changed

Cargo.toml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,11 @@ exclude = ["examples"]
1414
[workspace.dependencies]
1515
base64 = "0.22"
1616
bytes = "1"
17-
chrono = "0.4.35"
17+
chrono = { version = "0.4.35", default-features = false, features = [
18+
"clock",
19+
"serde",
20+
"std",
21+
] }
1822
futures = "0.3"
1923
futures-channel = "0.3"
2024
futures-util = "0.3"

examples/advanced-sqs-multiple-functions-shared-data/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
[workspace]
2+
resolver = "2"
23

34
members = [
45
"producer",
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/target
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
[package]
2+
name = "basic-error-diagnostic"
3+
version = "0.1.0"
4+
edition = "2021"
5+
6+
# Starting in Rust 1.62 you can use `cargo add` to add dependencies
7+
# to your project.
8+
#
9+
# If you're using an older Rust version,
10+
# download cargo-edit(https://github.com/killercup/cargo-edit#installation)
11+
# to install the `add` subcommand.
12+
#
13+
# Running `cargo add DEPENDENCY_NAME` will
14+
# add the latest version of a dependency to the list,
15+
# and it will keep the alphabetic ordering for you.
16+
17+
[dependencies]
18+
19+
lambda_runtime = { path = "../../lambda-runtime" }
20+
serde = "1"
21+
thiserror = "1.0.61"
22+
tokio = { version = "1", features = ["macros"] }
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# AWS Lambda Function Error handling example
2+
3+
This example shows how to implement the `Diagnostic` trait to return a specific `error_type` in the Lambda error response. If you don't use the `error_type` field, you don't need to implement `Diagnostic`, the type will be generated based on the error type name.
4+
5+
## Build & Deploy
6+
7+
1. Install [cargo-lambda](https://github.com/cargo-lambda/cargo-lambda#installation)
8+
2. Build the function with `cargo lambda build --release`
9+
3. Deploy the function to AWS Lambda with `cargo lambda deploy --iam-role YOUR_ROLE`
10+
11+
## Build for ARM 64
12+
13+
Build the function with `cargo lambda build --release --arm64`
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
use lambda_runtime::{service_fn, Diagnostic, Error, LambdaEvent};
2+
use serde::Deserialize;
3+
use thiserror;
4+
5+
#[derive(Deserialize)]
6+
struct Request {}
7+
8+
#[derive(Debug, thiserror::Error)]
9+
pub enum ExecutionError {
10+
#[error("transient database error: {0}")]
11+
DatabaseError(String),
12+
#[error("unexpected error: {0}")]
13+
Unexpected(String),
14+
}
15+
16+
impl<'a> From<ExecutionError> for Diagnostic<'a> {
17+
fn from(value: ExecutionError) -> Diagnostic<'a> {
18+
let (error_type, error_message) = match value {
19+
ExecutionError::DatabaseError(err) => ("Retryable", err.to_string()),
20+
ExecutionError::Unexpected(err) => ("NonRetryable", err.to_string()),
21+
};
22+
Diagnostic {
23+
error_type: error_type.into(),
24+
error_message: error_message.into(),
25+
}
26+
}
27+
}
28+
29+
/// This is the main body for the Lambda function
30+
async fn function_handler(_event: LambdaEvent<Request>) -> Result<(), ExecutionError> {
31+
Err(ExecutionError::Unexpected("ooops".to_string()))
32+
}
33+
34+
#[tokio::main]
35+
async fn main() -> Result<(), Error> {
36+
lambda_runtime::run(service_fn(function_handler)).await
37+
}

examples/basic-error-handling/README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
# AWS Lambda Function example
1+
# AWS Lambda Function Error handling example
2+
3+
This example shows how to return a custom error type for unexpected failures.
24

35
## Build & Deploy
46

examples/basic-error-handling/src/main.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/// See https://github.com/awslabs/aws-lambda-rust-runtime for more info on Rust runtime for AWS Lambda
22
use lambda_runtime::{service_fn, tracing, Error, LambdaEvent};
33
use serde::{Deserialize, Serialize};
4-
use serde_json::{json, Value};
4+
use serde_json::json;
55
use std::fs::File;
66

77
/// A simple Lambda request structure with just one field
@@ -59,11 +59,11 @@ async fn main() -> Result<(), Error> {
5959
}
6060

6161
/// The actual handler of the Lambda request.
62-
pub(crate) async fn func(event: LambdaEvent<Value>) -> Result<Value, Error> {
62+
pub(crate) async fn func(event: LambdaEvent<Request>) -> Result<Response, Error> {
6363
let (event, ctx) = event.into_parts();
6464

6565
// check what action was requested
66-
match serde_json::from_value::<Request>(event)?.event_type {
66+
match event.event_type {
6767
EventType::SimpleError => {
6868
// generate a simple text message error using `simple_error` crate
6969
return Err(Box::new(simple_error::SimpleError::new("A simple error as requested!")));
@@ -94,7 +94,7 @@ pub(crate) async fn func(event: LambdaEvent<Value>) -> Result<Value, Error> {
9494
msg: "OK".into(),
9595
};
9696

97-
return Ok(json!(resp));
97+
return Ok(resp);
9898
}
9999
}
100100
}

lambda-events/Cargo.toml

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,7 @@ edition = "2021"
1818
[dependencies]
1919
base64 = { workspace = true }
2020
bytes = { workspace = true, features = ["serde"], optional = true }
21-
chrono = { workspace = true, default-features = false, features = [
22-
"clock",
23-
"serde",
24-
"std",
25-
], optional = true }
21+
chrono = { workspace = true, optional = true }
2622
flate2 = { version = "1.0.24", optional = true }
2723
http = { workspace = true, optional = true }
2824
http-body = { workspace = true, optional = true }

lambda-http/src/lib.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ pub use http::{self, Response};
6868
/// Utilities to initialize and use `tracing` and `tracing-subscriber` in Lambda Functions.
6969
#[cfg(feature = "tracing")]
7070
pub use lambda_runtime::tracing;
71+
use lambda_runtime::Diagnostic;
7172
pub use lambda_runtime::{self, service_fn, tower, Context, Error, LambdaEvent, Service};
7273
use request::RequestFuture;
7374
use response::ResponseFuture;
@@ -193,7 +194,7 @@ where
193194
S: Service<Request, Response = R, Error = E>,
194195
S::Future: Send + 'a,
195196
R: IntoResponse,
196-
E: std::fmt::Debug + std::fmt::Display,
197+
E: std::fmt::Debug + for<'b> Into<Diagnostic<'b>>,
197198
{
198199
lambda_runtime::run(Adapter::from(handler)).await
199200
}

0 commit comments

Comments
 (0)