From a77abb1a0df8512120a5cb7875ec1c514ece227d Mon Sep 17 00:00:00 2001 From: sapessi Date: Sun, 2 Dec 2018 15:50:25 -0800 Subject: [PATCH 01/14] Fixed typo for UNHANDLED error constant --- lambda-runtime-client/src/error.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lambda-runtime-client/src/error.rs b/lambda-runtime-client/src/error.rs index 5a2bc573..13fc0531 100644 --- a/lambda-runtime-client/src/error.rs +++ b/lambda-runtime-client/src/error.rs @@ -13,7 +13,7 @@ use serde_json; pub const ERROR_TYPE_HANDLED: &str = "Handled"; /// Error type description for the `ErrorResponse` event. This type is used for unhandled, /// unexpcted errors. -pub const ERROR_TYPE_UNHANDLED: &str = "Handled"; +pub const ERROR_TYPE_UNHANDLED: &str = "Unhandled"; /// This object is used to generate requests to the Lambda Runtime APIs. /// It is used for both the error response APIs and fail init calls. From 36bcc8fbb41a2bf9276b696b021e0dd5577a3fb4 Mon Sep 17 00:00:00 2001 From: sapessi Date: Mon, 3 Dec 2018 10:00:52 -0800 Subject: [PATCH 02/14] Removed RuntimeApiError trait form the client and changed it to receive ErrorReponse directly --- lambda-runtime-client/src/client.rs | 18 +++++++++--------- lambda-runtime-client/src/error.rs | 29 ++++++++++++----------------- 2 files changed, 21 insertions(+), 26 deletions(-) diff --git a/lambda-runtime-client/src/client.rs b/lambda-runtime-client/src/client.rs index 95471dc2..2aa3cc49 100644 --- a/lambda-runtime-client/src/client.rs +++ b/lambda-runtime-client/src/client.rs @@ -1,4 +1,4 @@ -use error::{ApiError, ErrorResponse, RuntimeApiError}; +use error::{ApiError, ErrorResponse}; use hyper::{ client::HttpConnector, header::{self, HeaderMap, HeaderValue}, @@ -250,7 +250,7 @@ impl RuntimeClient { /// /// # Returns /// A `Result` object containing a bool return value for the call or an `error::ApiError` instance. - pub fn event_error(&self, request_id: &str, e: &RuntimeApiError) -> Result<(), ApiError> { + pub fn event_error(&self, request_id: &str, e: ErrorResponse) -> Result<(), ApiError> { let uri: Uri = format!( "http://{}/{}/runtime/invocation/{}/error", self.endpoint, RUNTIME_API_VERSION, request_id @@ -259,9 +259,9 @@ impl RuntimeClient { trace!( "Posting error to runtime API for request {}: {}", request_id, - e.to_response().error_message + e.error_message ); - let req = self.get_runtime_error_request(&uri, &e.to_response()); + let req = self.get_runtime_error_request(&uri, e); match self.http_client.request(req).wait() { Ok(resp) => { @@ -297,12 +297,12 @@ impl RuntimeClient { /// # Panics /// If it cannot send the init error. In this case we panic to force the runtime /// to restart. - pub fn fail_init(&self, e: &RuntimeApiError) { + pub fn fail_init(&self, e: ErrorResponse) { let uri: Uri = format!("http://{}/{}/runtime/init/error", self.endpoint, RUNTIME_API_VERSION) .parse() .expect("Could not generate Runtime URI"); - error!("Calling fail_init Runtime API: {}", e.to_response().error_message); - let req = self.get_runtime_error_request(&uri, &e.to_response()); + error!("Calling fail_init Runtime API: {}", e.error_message); + let req = self.get_runtime_error_request(&uri, e); self.http_client .request(req) @@ -343,8 +343,8 @@ impl RuntimeClient { .unwrap() } - fn get_runtime_error_request(&self, uri: &Uri, e: &ErrorResponse) -> Request { - let body = serde_json::to_vec(e).expect("Could not turn error object into response JSON"); + fn get_runtime_error_request(&self, uri: &Uri, e: ErrorResponse) -> Request { + let body = serde_json::to_vec(&e).expect("Could not turn error object into response JSON"); Request::builder() .method(Method::POST) .uri(uri.clone()) diff --git a/lambda-runtime-client/src/error.rs b/lambda-runtime-client/src/error.rs index 13fc0531..086e9b8a 100644 --- a/lambda-runtime-client/src/error.rs +++ b/lambda-runtime-client/src/error.rs @@ -69,16 +69,10 @@ impl ErrorResponse { } } -/// Custom errors for the framework should implement this trait. The client calls -/// the `to_response()` method automatically to produce an object that can be serialized -/// and sent to the Lambda Runtime APIs. -pub trait RuntimeApiError { - /// Creates a `RuntimeError` object for the current error. This is - /// then serialized and sent to the Lambda runtime APIs. - /// - /// # Returns - /// A populated `RuntimeError` object. - fn to_response(&self) -> ErrorResponse; +impl From> for ErrorResponse { + fn from(e: Box) -> Self { + Self::handled(e.description().to_owned()) + } } /// Represents an error generated by the Lambda Runtime API client. @@ -171,13 +165,14 @@ impl From for ApiError { } } -impl RuntimeApiError for ApiError { - fn to_response(&self) -> ErrorResponse { - let backtrace = format!("{:?}", self.backtrace); - let trace_vec = backtrace.lines().map(|s| s.to_string()).collect::>(); - let mut err = ErrorResponse::unhandled(self.msg.clone()); - err.stack_trace = Option::from(trace_vec); - +impl Into for ApiError { + fn into(self) -> ErrorResponse { + let mut err = ErrorResponse::unhandled(self.description().to_owned()); + if self.backtrace.is_some() { + let backtrace = format!("{:?}", self.backtrace); + let trace_vec = backtrace.lines().map(|s| s.to_string()).collect::>(); + err.stack_trace = Option::from(trace_vec); + } err } } From f53bd302774a90306e29f62e876dd1a10f60a4eb Mon Sep 17 00:00:00 2001 From: sapessi Date: Mon, 3 Dec 2018 10:01:40 -0800 Subject: [PATCH 03/14] Changed HandlerError type to alias Box to allow the runtime to handle any error type --- lambda-runtime/src/context.rs | 18 -------- lambda-runtime/src/error.rs | 85 +++++++---------------------------- lambda-runtime/src/runtime.rs | 17 ++++--- 3 files changed, 25 insertions(+), 95 deletions(-) diff --git a/lambda-runtime/src/context.rs b/lambda-runtime/src/context.rs index 88e699a6..75ea16e3 100644 --- a/lambda-runtime/src/context.rs +++ b/lambda-runtime/src/context.rs @@ -1,10 +1,6 @@ -use std::env; - use chrono::Utc; -use backtrace; use env as lambda_env; -use error::HandlerError; use lambda_runtime_client; /// The Lambda function execution context. The values in this struct @@ -86,20 +82,6 @@ impl Context { } } - /// We use the context for each event to store the stack trace. This is the methods - /// clients should use to retrieve an initialized `RuntimeError` with the populated - /// stack trace. - pub fn new_error(&self, msg: &str) -> HandlerError { - let mut trace: Option = None; - let is_backtrace = env::var("RUST_BACKTRACE"); - if is_backtrace.is_ok() && is_backtrace.unwrap() == "1" { - trace!("Begin backtrace collection"); - trace = Option::from(backtrace::Backtrace::new()); - trace!("Completed backtrace collection"); - } - HandlerError::new(msg, trace) - } - /// Returns the remaining time in the execution in milliseconds. This is based on the /// deadline header passed by Lambda's Runtime APIs. pub fn get_time_remaining_millis(&self) -> u128 { diff --git a/lambda-runtime/src/error.rs b/lambda-runtime/src/error.rs index 2e00dcf4..a8eeed8e 100644 --- a/lambda-runtime/src/error.rs +++ b/lambda-runtime/src/error.rs @@ -3,9 +3,12 @@ use std::{env, error::Error, fmt}; use backtrace; -use lambda_runtime_client::error; +use lambda_runtime_client::error::{ApiError, ErrorResponse}; use serde_json; +/// Abstration for the handler error +pub type HandlerError = Box; + /// The `RuntimeError` object is returned by the custom runtime as it polls /// for new events and tries to execute the handler function. The error /// is primarily used by other methods within this crate and should not be relevant @@ -14,7 +17,7 @@ use serde_json; #[derive(Debug, Clone)] pub struct RuntimeError { msg: String, - stack_trace: Option, + backtrace: Option, /// The request id that generated this error pub(crate) request_id: Option, /// Whether the error is recoverable or not. @@ -58,21 +61,22 @@ impl RuntimeError { } RuntimeError { msg: String::from(msg), - stack_trace: trace, + backtrace: trace, recoverable: true, request_id: None, } } } -impl error::RuntimeApiError for RuntimeError { - fn to_response(&self) -> error::ErrorResponse { - let backtrace = format!("{:?}", self.stack_trace); - error::ErrorResponse { - error_message: String::from(self.description()), - error_type: String::from(error::ERROR_TYPE_HANDLED), - stack_trace: Option::from(backtrace.lines().map(|s| s.to_string()).collect::>()), +impl Into for RuntimeError { + fn into(self) -> ErrorResponse { + let mut err = ErrorResponse::unhandled(self.description().to_owned()); + if self.backtrace.is_some() { + let backtrace = format!("{:?}", self.backtrace); + let trace_vec = backtrace.lines().map(|s| s.to_string()).collect::>(); + err.stack_trace = Option::from(trace_vec); } + err } } @@ -106,66 +110,11 @@ impl From for RuntimeError { } } -impl From for RuntimeError { - fn from(e: error::ApiError) -> Self { +impl From for RuntimeError { + fn from(e: ApiError) -> Self { let mut err = RuntimeError::new(e.description()); err.recoverable = e.recoverable; - err.stack_trace = e.backtrace; + err.backtrace = e.backtrace; err } } - -/// The error type for functions that are used as the `Handler` type. New errors -/// should be instantiated using the `new_error()` method of the `runtime::Context` -/// object passed to the handler function. -#[derive(Debug, Clone)] -pub struct HandlerError { - msg: String, - backtrace: Option, -} - -impl fmt::Display for HandlerError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}", self.msg) - } -} - -// This is important for other errors to wrap this one. -impl Error for HandlerError { - fn description(&self) -> &str { - &self.msg - } - - fn cause(&self) -> Option<&Error> { - // Generic error, underlying cause isn't tracked. - None - } -} - -impl HandlerError { - /// Creates a new handler error. This method is used by the `new_error()` method - /// of the `runtime::Context` object. - /// - /// # Arguments - /// - /// * `msg` The error message for the new error - /// * `trace` A `Backtrace` object to generate the stack trace for the error - /// response. This is provided by the `Context` object. - pub(crate) fn new(msg: &str, trace: Option) -> HandlerError { - HandlerError { - msg: msg.to_string(), - backtrace: trace, - } - } -} - -impl error::RuntimeApiError for HandlerError { - fn to_response(&self) -> error::ErrorResponse { - let backtrace = format!("{:?}", self.backtrace); - error::ErrorResponse { - error_message: String::from(self.description()), - error_type: String::from(error::ERROR_TYPE_HANDLED), - stack_trace: Option::from(backtrace.lines().map(|s| s.to_string()).collect::>()), - } - } -} diff --git a/lambda-runtime/src/runtime.rs b/lambda-runtime/src/runtime.rs index 770788f4..07979df5 100644 --- a/lambda-runtime/src/runtime.rs +++ b/lambda-runtime/src/runtime.rs @@ -1,4 +1,4 @@ -use std::{error::Error, marker::PhantomData, result}; +use std::{marker::PhantomData, result}; use serde; use serde_json; @@ -6,7 +6,7 @@ use serde_json; use context::Context; use env::{ConfigProvider, EnvConfigProvider, FunctionSettings}; use error::{HandlerError, RuntimeError}; -use lambda_runtime_client::RuntimeClient; +use lambda_runtime_client::{error::ErrorResponse, RuntimeClient}; use tokio::runtime::Runtime as TokioRuntime; const MAX_RETRIES: i8 = 3; @@ -215,7 +215,7 @@ where "Error for {} is not recoverable, sending fail_init signal and panicking.", request_id ); - self.runtime_client.fail_init(&e); + self.runtime_client.fail_init(ErrorResponse::from(Box::from(e))); panic!("Could not send response"); } } @@ -226,8 +226,7 @@ where "Could not marshal output object to Vec JSON represnetation for request {}: {}", request_id, e ); - self.runtime_client - .fail_init(&RuntimeError::unrecoverable(e.description())); + self.runtime_client.fail_init(ErrorResponse::from(Box::from(e))); panic!("Failed to marshal handler output, panic"); } } @@ -235,7 +234,7 @@ where Err(e) => { debug!("Handler returned an error for {}: {}", request_id, e); debug!("Attempting to send error response to Runtime API for {}", request_id); - match self.runtime_client.event_error(&request_id, &e) { + match self.runtime_client.event_error(&request_id, ErrorResponse::from(e)) { Ok(_) => info!("Error response for {} accepted by Runtime API", request_id), Err(e) => { error!("Unable to send error response for {} to Runtime API: {}", request_id, e); @@ -244,7 +243,7 @@ where "Error for {} is not recoverable, sending fail_init signal and panicking", request_id ); - self.runtime_client.fail_init(&e); + self.runtime_client.fail_init(ErrorResponse::from(Box::from(e))); panic!("Could not send error response"); } } @@ -272,11 +271,11 @@ where match err.request_id.clone() { Some(req_id) => { self.runtime_client - .event_error(&req_id, &err) + .event_error(&req_id, ErrorResponse::from(Box::from(err))) .expect("Could not send event error response"); } None => { - self.runtime_client.fail_init(&err); + self.runtime_client.fail_init(ErrorResponse::from(Box::from(err))); } } From 8b6d8fc01cbfaa1736707aaa7ffdaa776d3eb17b Mon Sep 17 00:00:00 2001 From: sapessi Date: Mon, 3 Dec 2018 10:02:17 -0800 Subject: [PATCH 04/14] Added custom error examples and updated existing examples --- Cargo.lock | 9 +++ lambda-runtime/Cargo.toml | 3 + lambda-runtime/examples/basic.rs | 4 +- lambda-runtime/examples/custom_error.rs | 70 +++++++++++++++++++ .../examples/custom_error_failure.rs | 47 +++++++++++++ .../examples/with_custom_runtime.rs | 4 +- 6 files changed, 135 insertions(+), 2 deletions(-) create mode 100644 lambda-runtime/examples/custom_error.rs create mode 100644 lambda-runtime/examples/custom_error_failure.rs diff --git a/Cargo.lock b/Cargo.lock index 2bb0f9f3..4a6e4ae1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -411,6 +411,8 @@ version = "0.1.0" dependencies = [ "backtrace 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "failure_derive 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "hyper 0.12.12 (registry+https://github.com/rust-lang/crates.io-index)", "hyper-tls 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "lambda_runtime_client 0.1.0", @@ -420,6 +422,7 @@ dependencies = [ "serde 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.31 (registry+https://github.com/rust-lang/crates.io-index)", + "simple-error 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", "simple_logger 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "tokio 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -909,6 +912,11 @@ dependencies = [ "fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "simple-error" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "simple_logger" version = "1.0.1" @@ -1377,6 +1385,7 @@ dependencies = [ "checksum serde_derive 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)" = "31569d901045afbff7a9479f793177fe9259819aff10ab4f89ef69bbc5f567fe" "checksum serde_json 1.0.31 (registry+https://github.com/rust-lang/crates.io-index)" = "bb47a3d5c84320222f66d7db21157c4a7407755de41798f9b4c1c40593397b1a" "checksum sha2 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9eb6be24e4c23a84d7184280d2722f7f2731fcdd4a9d886efbfe4413e4847ea0" +"checksum simple-error 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "01c1c2ededd95f93b1d65e7f8b5b17670e926bf9cbb55f8b91b26b0bd40d3259" "checksum simple_logger 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "25111f1d77db1ac3ee11b62ba4b7a162e6bb3be43e28273f0d3935cc8d3ff7fb" "checksum slab 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5f9776d6b986f77b35c6cf846c11ad986ff128fe0b2b63a3628e3755e8d3102d" "checksum smallvec 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "153ffa32fd170e9944f7e0838edf824a754ec4c1fc64746fcc9fe1f8fa602e5d" diff --git a/lambda-runtime/Cargo.toml b/lambda-runtime/Cargo.toml index 5acd7778..59167d47 100644 --- a/lambda-runtime/Cargo.toml +++ b/lambda-runtime/Cargo.toml @@ -23,5 +23,8 @@ simple_logger = "^1" [dev-dependencies] hyper-tls = "^0.3" +simple-error = "^0.1" +failure = "^0.1" +failure_derive = "^0.1" rusoto_core = "^0.35" rusoto_dynamodb = "^0.35" diff --git a/lambda-runtime/examples/basic.rs b/lambda-runtime/examples/basic.rs index 83736a45..c1c01a4b 100644 --- a/lambda-runtime/examples/basic.rs +++ b/lambda-runtime/examples/basic.rs @@ -1,6 +1,8 @@ extern crate lambda_runtime as lambda; extern crate log; extern crate serde_derive; +#[macro_use] +extern crate simple_error; extern crate simple_logger; use lambda::{error::HandlerError, lambda}; @@ -29,7 +31,7 @@ fn main() -> Result<(), Box> { fn my_handler(e: CustomEvent, c: lambda::Context) -> Result { if e.first_name == "" { error!("Empty first name in request {}", c.aws_request_id); - return Err(c.new_error("Empty first name")); + bail!("Empty first name"); } Ok(CustomOutput { diff --git a/lambda-runtime/examples/custom_error.rs b/lambda-runtime/examples/custom_error.rs new file mode 100644 index 00000000..54377c06 --- /dev/null +++ b/lambda-runtime/examples/custom_error.rs @@ -0,0 +1,70 @@ +extern crate lambda_runtime as lambda; +extern crate log; +extern crate serde_derive; +extern crate simple_logger; + +use lambda::{error::HandlerError, lambda}; +use log::error; +use serde_derive::{Deserialize, Serialize}; +use std::{error::Error, fmt}; + +#[derive(Debug)] +struct CustomError { + msg: String, +} + +impl fmt::Display for CustomError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.msg) + } +} + +impl Error for CustomError {} + +impl CustomError { + fn new(message: &str) -> CustomError { + CustomError { + msg: message.to_owned(), + } + } + + fn boxed(self) -> Box { + Box::from(self) + } +} + +#[derive(Deserialize)] +struct CustomEvent { + #[serde(rename = "firstName")] + first_name: String, + age: String, +} + +#[derive(Serialize)] +struct CustomOutput { + message: String, +} + +fn main() -> Result<(), Box> { + simple_logger::init_with_level(log::Level::Debug).unwrap(); + lambda!(my_handler); + + Ok(()) +} + +fn my_handler(e: CustomEvent, c: lambda::Context) -> Result { + if e.first_name == "" { + error!("Empty first name in request {}", c.aws_request_id); + // in this case, we explicitly initialize and box our custom error type. + // the HandlerError type is an alias to Box/ + return Err(CustomError::new("Empty first name").boxed()); + } + + // For errors simply want to return, because the HandlerError is an alias to any + // generic error type, we can propapgate with the standard "?" syntax. + let _age_num: u8 = e.age.parse()?; + + Ok(CustomOutput { + message: format!("Hello, {}!", e.first_name), + }) +} diff --git a/lambda-runtime/examples/custom_error_failure.rs b/lambda-runtime/examples/custom_error_failure.rs new file mode 100644 index 00000000..3464b79b --- /dev/null +++ b/lambda-runtime/examples/custom_error_failure.rs @@ -0,0 +1,47 @@ +extern crate lambda_runtime as lambda; +extern crate log; +extern crate serde_derive; +extern crate simple_logger; +#[macro_use] +extern crate failure; + +use lambda::{error::HandlerError, lambda}; +use log::error; +use serde_derive::{Deserialize, Serialize}; +use failure::Error; + +#[derive(Fail, Debug)] +#[fail(display = "Custom Error")] +struct CustomError; + +#[derive(Deserialize)] +struct CustomEvent { + #[serde(rename = "firstName")] + first_name: String, + age: String, +} + +#[derive(Serialize)] +struct CustomOutput { + message: String, +} + +fn main() -> Result<(), Box> { + simple_logger::init_with_level(log::Level::Debug).unwrap(); + lambda!(my_handler); + + Ok(()) +} + +fn my_handler(e: CustomEvent, c: lambda::Context) -> Result { + if e.first_name == "" { + error!("Empty first name in request {}", c.aws_request_id); + return Err(CustomError{}); + } + + let _age_num: u8 = e.age.parse()?; + + Ok(CustomOutput { + message: format!("Hello, {}!", e.first_name), + }) +} diff --git a/lambda-runtime/examples/with_custom_runtime.rs b/lambda-runtime/examples/with_custom_runtime.rs index 599e0556..48101ddf 100644 --- a/lambda-runtime/examples/with_custom_runtime.rs +++ b/lambda-runtime/examples/with_custom_runtime.rs @@ -2,6 +2,8 @@ extern crate lambda_runtime as lambda; extern crate log; extern crate serde_derive; extern crate simple_logger; +#[macro_use] +extern crate simple_error; extern crate tokio; use lambda::{error::HandlerError, lambda}; @@ -33,7 +35,7 @@ fn main() -> Result<(), Box> { fn my_handler(e: CustomEvent, c: lambda::Context) -> Result { if e.first_name == "" { error!("Empty first name in request {}", c.aws_request_id); - return Err(c.new_error("Empty first name")); + bail!("Empty first name"); } Ok(CustomOutput { From 2e034d280eeaadd8b9b2903ba9dbefe23f84b700 Mon Sep 17 00:00:00 2001 From: sapessi Date: Mon, 3 Dec 2018 10:20:11 -0800 Subject: [PATCH 05/14] Fixed failure example --- lambda-runtime/examples/custom_error_failure.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lambda-runtime/examples/custom_error_failure.rs b/lambda-runtime/examples/custom_error_failure.rs index 3464b79b..b625c64c 100644 --- a/lambda-runtime/examples/custom_error_failure.rs +++ b/lambda-runtime/examples/custom_error_failure.rs @@ -5,9 +5,10 @@ extern crate simple_logger; #[macro_use] extern crate failure; -use lambda::{error::HandlerError, lambda}; +use lambda::lambda; use log::error; use serde_derive::{Deserialize, Serialize}; +use std::error::Error as StdError; use failure::Error; #[derive(Fail, Debug)] @@ -26,7 +27,7 @@ struct CustomOutput { message: String, } -fn main() -> Result<(), Box> { +fn main() -> Result<(), Box> { simple_logger::init_with_level(log::Level::Debug).unwrap(); lambda!(my_handler); From 4f20464f72cc78feb9a8c6b7f2de5c4934c0e9c1 Mon Sep 17 00:00:00 2001 From: sapessi Date: Mon, 3 Dec 2018 10:25:02 -0800 Subject: [PATCH 06/14] Updated comment on HandlerError type --- lambda-runtime/src/error.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lambda-runtime/src/error.rs b/lambda-runtime/src/error.rs index a8eeed8e..2dd1c4ff 100644 --- a/lambda-runtime/src/error.rs +++ b/lambda-runtime/src/error.rs @@ -6,7 +6,10 @@ use backtrace; use lambda_runtime_client::error::{ApiError, ErrorResponse}; use serde_json; -/// Abstration for the handler error +/// The `HandlerError` type can be use to abstract any error in the handler method. +/// This allows handler functions to return any error using the `?` syntax. For example +/// `let _age_num: u8 = e.age.parse()?;` will return the `::Err` from the +/// handler function. pub type HandlerError = Box; /// The `RuntimeError` object is returned by the custom runtime as it polls From d17b7c8cdde793a0bf187eddc52521ff5f36d1be Mon Sep 17 00:00:00 2001 From: sapessi Date: Mon, 3 Dec 2018 10:25:32 -0800 Subject: [PATCH 07/14] Exported HandlerError in root of the crate --- lambda-runtime/examples/basic.rs | 2 +- lambda-runtime/examples/custom_error.rs | 2 +- lambda-runtime/examples/with_custom_runtime.rs | 2 +- lambda-runtime/src/lib.rs | 3 ++- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/lambda-runtime/examples/basic.rs b/lambda-runtime/examples/basic.rs index c1c01a4b..879a5675 100644 --- a/lambda-runtime/examples/basic.rs +++ b/lambda-runtime/examples/basic.rs @@ -5,7 +5,7 @@ extern crate serde_derive; extern crate simple_error; extern crate simple_logger; -use lambda::{error::HandlerError, lambda}; +use lambda::{lambda, HandlerError}; use log::error; use serde_derive::{Deserialize, Serialize}; use std::error::Error; diff --git a/lambda-runtime/examples/custom_error.rs b/lambda-runtime/examples/custom_error.rs index 54377c06..1eee9157 100644 --- a/lambda-runtime/examples/custom_error.rs +++ b/lambda-runtime/examples/custom_error.rs @@ -3,7 +3,7 @@ extern crate log; extern crate serde_derive; extern crate simple_logger; -use lambda::{error::HandlerError, lambda}; +use lambda::{lambda, HandlerError}; use log::error; use serde_derive::{Deserialize, Serialize}; use std::{error::Error, fmt}; diff --git a/lambda-runtime/examples/with_custom_runtime.rs b/lambda-runtime/examples/with_custom_runtime.rs index 48101ddf..666f56ec 100644 --- a/lambda-runtime/examples/with_custom_runtime.rs +++ b/lambda-runtime/examples/with_custom_runtime.rs @@ -6,7 +6,7 @@ extern crate simple_logger; extern crate simple_error; extern crate tokio; -use lambda::{error::HandlerError, lambda}; +use lambda::{lambda, HandlerError}; use log::error; use serde_derive::{Deserialize, Serialize}; use std::error::Error; diff --git a/lambda-runtime/src/lib.rs b/lambda-runtime/src/lib.rs index 36448d00..0c5b1ea3 100644 --- a/lambda-runtime/src/lib.rs +++ b/lambda-runtime/src/lib.rs @@ -51,8 +51,9 @@ extern crate tokio; mod context; mod env; -pub mod error; +mod error; mod runtime; pub use context::*; +pub use error::HandlerError; pub use runtime::*; From 08772e9046260755acc21c0e49a2c2915c5842d6 Mon Sep 17 00:00:00 2001 From: sapessi Date: Mon, 3 Dec 2018 11:31:33 -0800 Subject: [PATCH 08/14] Added error code to response structure and centralized backtrace generation to the new() function on the ErrorResponse --- lambda-runtime-client/src/client.rs | 2 +- lambda-runtime-client/src/error.rs | 72 ++++++++++++++++------------- lambda-runtime/src/error.rs | 25 +--------- 3 files changed, 41 insertions(+), 58 deletions(-) diff --git a/lambda-runtime-client/src/client.rs b/lambda-runtime-client/src/client.rs index 2aa3cc49..0b89e990 100644 --- a/lambda-runtime-client/src/client.rs +++ b/lambda-runtime-client/src/client.rs @@ -352,7 +352,7 @@ impl RuntimeClient { header::CONTENT_TYPE, header::HeaderValue::from_static(API_ERROR_CONTENT_TYPE), ) - .header(RUNTIME_ERROR_HEADER, HeaderValue::from_static("RuntimeError")) // TODO: We should add this code to the error object. + .header(RUNTIME_ERROR_HEADER, e.error_code) .body(Body::from(body)) .unwrap() } diff --git a/lambda-runtime-client/src/error.rs b/lambda-runtime-client/src/error.rs index 086e9b8a..0c92d12f 100644 --- a/lambda-runtime-client/src/error.rs +++ b/lambda-runtime-client/src/error.rs @@ -21,6 +21,10 @@ pub const ERROR_TYPE_UNHANDLED: &str = "Unhandled"; /// this object to be compatible with the APIs. #[derive(Serialize)] pub struct ErrorResponse { + /// Internal error code to be sent to the Lambda Runtime APIs in the + /// `Lambda-Runtime-Function-Error-Type` header. + #[serde(skip)] + pub error_code: String, /// The error message generated by the application. #[serde(rename = "errorMessage")] pub error_message: String, @@ -36,6 +40,39 @@ pub struct ErrorResponse { } impl ErrorResponse { + /// Creates a new instance of the `ErrorResponse` object with the given parameters. If the + /// `RUST_BACKTRACE` env variable is `1` the `ErrorResponse` is populated with the backtrace + /// collected through the [`backtrace` craete](https://crates.io/crates/backtrace). + /// + /// # Arguments + /// + /// * `message` The error message to be returned to the APIs. Normally the error description() + /// * `err_type` The error type. Use the `ERROR_TYPE_HANDLED` and `ERROR_TYPE_UNHANDLED`. + /// * `code` A custom error code + /// + /// # Return + /// A new instance of the `ErrorResponse` object. + fn new(message: String, err_type: String, code: String) -> ErrorResponse { + let mut err = ErrorResponse { + error_message: message, + error_type: err_type, + error_code: code, + stack_trace: Option::default(), + }; + let is_backtrace = env::var("RUST_BACKTRACE"); + if is_backtrace.is_ok() && is_backtrace.unwrap() == "1" { + trace!("Begin backtrace collection"); + let trace = Option::from(backtrace::Backtrace::new()); + let trace_string = format!("{:?}", trace) + .lines() + .map(|s| s.to_string()) + .collect::>(); + trace!("Completed backtrace collection"); + err.stack_trace = Option::from(trace_string); + } + err + } + /// Creates a new `RuntimeError` object with the handled error type. /// /// # Arguments @@ -45,11 +82,7 @@ impl ErrorResponse { /// # Return /// A populated `RuntimeError` object that can be used with the Lambda Runtime API. pub fn handled(message: String) -> ErrorResponse { - ErrorResponse { - error_message: message, - error_type: String::from(ERROR_TYPE_HANDLED), - stack_trace: Option::default(), - } + ErrorResponse::new(message, ERROR_TYPE_HANDLED.to_owned(), "RuntimeError".to_owned()) } /// Creates a new `RuntimeError` object with the unhandled error type. @@ -61,11 +94,7 @@ impl ErrorResponse { /// # Return /// A populated `RuntimeError` object that can be used with the Lambda Runtime API. pub fn unhandled(message: String) -> ErrorResponse { - ErrorResponse { - error_message: message, - error_type: String::from(ERROR_TYPE_UNHANDLED), - stack_trace: Option::default(), - } + ErrorResponse::new(message, ERROR_TYPE_UNHANDLED.to_owned(), "RuntimeError".to_owned()) } } @@ -79,9 +108,6 @@ impl From> for ErrorResponse { #[derive(Debug, Clone)] pub struct ApiError { msg: String, - /// The `Backtrace` object from the `backtrace` crate used to store - /// the stack trace of the error. - pub backtrace: Option, /// Whether the current error is recoverable. If the error is not /// recoverable a runtime should panic to force the Lambda service /// to restart the execution environment. @@ -90,16 +116,8 @@ pub struct ApiError { impl ApiError { pub(crate) fn new(description: &str) -> ApiError { - let mut trace: Option = None; - let is_backtrace = env::var("RUST_BACKTRACE"); - if is_backtrace.is_ok() && is_backtrace.unwrap() == "1" { - trace!("Begin backtrace collection"); - trace = Option::from(backtrace::Backtrace::new()); - trace!("Completed backtrace collection"); - } ApiError { msg: String::from(description), - backtrace: trace, recoverable: true, } } @@ -164,15 +182,3 @@ impl From for ApiError { ApiError::new(e.description()) } } - -impl Into for ApiError { - fn into(self) -> ErrorResponse { - let mut err = ErrorResponse::unhandled(self.description().to_owned()); - if self.backtrace.is_some() { - let backtrace = format!("{:?}", self.backtrace); - let trace_vec = backtrace.lines().map(|s| s.to_string()).collect::>(); - err.stack_trace = Option::from(trace_vec); - } - err - } -} diff --git a/lambda-runtime/src/error.rs b/lambda-runtime/src/error.rs index 2dd1c4ff..9af05745 100644 --- a/lambda-runtime/src/error.rs +++ b/lambda-runtime/src/error.rs @@ -2,8 +2,7 @@ //! by custom handlers as well as the runtime itself. use std::{env, error::Error, fmt}; -use backtrace; -use lambda_runtime_client::error::{ApiError, ErrorResponse}; +use lambda_runtime_client::error::ApiError; use serde_json; /// The `HandlerError` type can be use to abstract any error in the handler method. @@ -20,7 +19,6 @@ pub type HandlerError = Box; #[derive(Debug, Clone)] pub struct RuntimeError { msg: String, - backtrace: Option, /// The request id that generated this error pub(crate) request_id: Option, /// Whether the error is recoverable or not. @@ -55,34 +53,14 @@ impl RuntimeError { /// # Returns /// A new `RuntimeError` instance. pub(crate) fn new(msg: &str) -> RuntimeError { - let mut trace: Option = None; - let is_backtrace = env::var("RUST_BACKTRACE"); - if is_backtrace.is_ok() && is_backtrace.unwrap() == "1" { - trace!("Begin backtrace collection"); - trace = Option::from(backtrace::Backtrace::new()); - trace!("Completed backtrace collection"); - } RuntimeError { msg: String::from(msg), - backtrace: trace, recoverable: true, request_id: None, } } } -impl Into for RuntimeError { - fn into(self) -> ErrorResponse { - let mut err = ErrorResponse::unhandled(self.description().to_owned()); - if self.backtrace.is_some() { - let backtrace = format!("{:?}", self.backtrace); - let trace_vec = backtrace.lines().map(|s| s.to_string()).collect::>(); - err.stack_trace = Option::from(trace_vec); - } - err - } -} - impl fmt::Display for RuntimeError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", self.msg) @@ -117,7 +95,6 @@ impl From for RuntimeError { fn from(e: ApiError) -> Self { let mut err = RuntimeError::new(e.description()); err.recoverable = e.recoverable; - err.backtrace = e.backtrace; err } } From a6d2c5b8668d68fd388774c22d62baa961f6d579 Mon Sep 17 00:00:00 2001 From: sapessi Date: Mon, 3 Dec 2018 11:38:17 -0800 Subject: [PATCH 09/14] Updated example in lib docs --- lambda-runtime/src/lib.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lambda-runtime/src/lib.rs b/lambda-runtime/src/lib.rs index 0c5b1ea3..beeb291e 100644 --- a/lambda-runtime/src/lib.rs +++ b/lambda-runtime/src/lib.rs @@ -11,8 +11,10 @@ //! extern crate serde_derive; //! #[macro_use] //! extern crate lambda_runtime; +//! #[macro_use] +//! extern crate simple_error; //! -//! use lambda_runtime::error::HandlerError; +//! use lambda_runtime::HandlerError; //! //! //! #[derive(Deserialize, Clone)] @@ -32,7 +34,7 @@ //! //! fn my_handler(e: CustomEvent, ctx: lambda_runtime::Context) -> Result { //! if e.first_name == "" { -//! return Err(ctx.new_error("Missing first name!")); +//! bail!("Empty first name"); //! } //! Ok(CustomOutput{ //! message: format!("Hello, {}!", e.first_name), From fee02e84df6a3d86848d5b79c2a03161c5354cc1 Mon Sep 17 00:00:00 2001 From: sapessi Date: Mon, 3 Dec 2018 11:38:35 -0800 Subject: [PATCH 10/14] Temporary fix for failure example --- lambda-runtime/examples/custom_error_failure.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lambda-runtime/examples/custom_error_failure.rs b/lambda-runtime/examples/custom_error_failure.rs index b625c64c..c7a66bb6 100644 --- a/lambda-runtime/examples/custom_error_failure.rs +++ b/lambda-runtime/examples/custom_error_failure.rs @@ -5,11 +5,11 @@ extern crate simple_logger; #[macro_use] extern crate failure; -use lambda::lambda; +use failure::Error; +use lambda::{lambda, HandlerError}; use log::error; use serde_derive::{Deserialize, Serialize}; use std::error::Error as StdError; -use failure::Error; #[derive(Fail, Debug)] #[fail(display = "Custom Error")] @@ -34,10 +34,10 @@ fn main() -> Result<(), Box> { Ok(()) } -fn my_handler(e: CustomEvent, c: lambda::Context) -> Result { +fn my_handler(e: CustomEvent, c: lambda::Context) -> Result { if e.first_name == "" { error!("Empty first name in request {}", c.aws_request_id); - return Err(CustomError{}); + return Err(Box::from(Error::from(CustomError {}).compat())); } let _age_num: u8 = e.age.parse()?; From 4969624e8d6920ddb0f8f1168ba8b78fe93f5c7b Mon Sep 17 00:00:00 2001 From: sapessi Date: Mon, 3 Dec 2018 21:16:11 -0800 Subject: [PATCH 11/14] Switched to HandlerError struct that can be created from any Display + Send + Sync + Debug. Updated samples to reflect this --- lambda-runtime-client/src/error.rs | 17 +++++++--- lambda-runtime/examples/custom_error.rs | 6 +--- .../examples/custom_error_failure.rs | 3 +- lambda-runtime/src/error.rs | 31 +++++++++++++++---- lambda-runtime/src/runtime.rs | 17 +++++----- 5 files changed, 50 insertions(+), 24 deletions(-) diff --git a/lambda-runtime-client/src/error.rs b/lambda-runtime-client/src/error.rs index 0c92d12f..422e6179 100644 --- a/lambda-runtime-client/src/error.rs +++ b/lambda-runtime-client/src/error.rs @@ -1,7 +1,14 @@ //! This module defines the `RuntimeApiError` trait that developers should implement //! to send their custom errors to the AWS Lambda Runtime Client SDK. The module also //! defines the `ApiError` type returned by the `RuntimeClient` implementations. -use std::{env, error::Error, fmt, io, num::ParseIntError, option::Option}; +use std::{ + env, + error::Error, + fmt::{self, Display}, + io, + num::ParseIntError, + option::Option, +}; use backtrace; use http::{header::ToStrError, uri::InvalidUri}; @@ -98,9 +105,9 @@ impl ErrorResponse { } } -impl From> for ErrorResponse { - fn from(e: Box) -> Self { - Self::handled(e.description().to_owned()) +impl From> for ErrorResponse { + fn from(e: Box) -> Self { + Self::handled(format!("{}", e)) } } @@ -146,6 +153,8 @@ impl Error for ApiError { None } } +unsafe impl Send for ApiError {} +unsafe impl Sync for ApiError {} impl From for ApiError { fn from(e: serde_json::Error) -> Self { diff --git a/lambda-runtime/examples/custom_error.rs b/lambda-runtime/examples/custom_error.rs index 1eee9157..d9e18783 100644 --- a/lambda-runtime/examples/custom_error.rs +++ b/lambda-runtime/examples/custom_error.rs @@ -27,10 +27,6 @@ impl CustomError { msg: message.to_owned(), } } - - fn boxed(self) -> Box { - Box::from(self) - } } #[derive(Deserialize)] @@ -57,7 +53,7 @@ fn my_handler(e: CustomEvent, c: lambda::Context) -> Result/ - return Err(CustomError::new("Empty first name").boxed()); + return Err(CustomError::new("Empty first name").into()); } // For errors simply want to return, because the HandlerError is an alias to any diff --git a/lambda-runtime/examples/custom_error_failure.rs b/lambda-runtime/examples/custom_error_failure.rs index c7a66bb6..f9bfa164 100644 --- a/lambda-runtime/examples/custom_error_failure.rs +++ b/lambda-runtime/examples/custom_error_failure.rs @@ -5,7 +5,6 @@ extern crate simple_logger; #[macro_use] extern crate failure; -use failure::Error; use lambda::{lambda, HandlerError}; use log::error; use serde_derive::{Deserialize, Serialize}; @@ -37,7 +36,7 @@ fn main() -> Result<(), Box> { fn my_handler(e: CustomEvent, c: lambda::Context) -> Result { if e.first_name == "" { error!("Empty first name in request {}", c.aws_request_id); - return Err(Box::from(Error::from(CustomError {}).compat())); + return Err((CustomError {}).into()); } let _age_num: u8 = e.age.parse()?; diff --git a/lambda-runtime/src/error.rs b/lambda-runtime/src/error.rs index 9af05745..ebbcd504 100644 --- a/lambda-runtime/src/error.rs +++ b/lambda-runtime/src/error.rs @@ -1,15 +1,34 @@ //! The error module defines the error types that can be returned //! by custom handlers as well as the runtime itself. -use std::{env, error::Error, fmt}; +use std::{ + env, + error::Error, + fmt::{self, Debug, Display}, +}; use lambda_runtime_client::error::ApiError; use serde_json; -/// The `HandlerError` type can be use to abstract any error in the handler method. -/// This allows handler functions to return any error using the `?` syntax. For example -/// `let _age_num: u8 = e.age.parse()?;` will return the `::Err` from the -/// handler function. -pub type HandlerError = Box; +/// The `HandlerError` struct can be use to abstract any `Err` of the handler method `Result`. +/// The `HandlerError` object can be generated `From` any object that supports `Display`, +/// `Send, `Sync`, and `Debug`. This allows handler functions to return any error using +/// the `?` syntax. For example `let _age_num: u8 = e.age.parse()?;` will return the +/// `::Err` from the handler function. +pub struct HandlerError { + msg: String, +} + +impl From for HandlerError { + fn from(e: E) -> HandlerError { + HandlerError { msg: format!("{}", e) } + } +} + +impl Display for HandlerError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.msg) + } +} /// The `RuntimeError` object is returned by the custom runtime as it polls /// for new events and tries to execute the handler function. The error diff --git a/lambda-runtime/src/runtime.rs b/lambda-runtime/src/runtime.rs index 07979df5..6b56a690 100644 --- a/lambda-runtime/src/runtime.rs +++ b/lambda-runtime/src/runtime.rs @@ -215,7 +215,7 @@ where "Error for {} is not recoverable, sending fail_init signal and panicking.", request_id ); - self.runtime_client.fail_init(ErrorResponse::from(Box::from(e))); + self.runtime_client.fail_init(ErrorResponse::from(Box::new(e))); panic!("Could not send response"); } } @@ -226,7 +226,7 @@ where "Could not marshal output object to Vec JSON represnetation for request {}: {}", request_id, e ); - self.runtime_client.fail_init(ErrorResponse::from(Box::from(e))); + self.runtime_client.fail_init(ErrorResponse::from(Box::new(e))); panic!("Failed to marshal handler output, panic"); } } @@ -234,7 +234,10 @@ where Err(e) => { debug!("Handler returned an error for {}: {}", request_id, e); debug!("Attempting to send error response to Runtime API for {}", request_id); - match self.runtime_client.event_error(&request_id, ErrorResponse::from(e)) { + match self + .runtime_client + .event_error(&request_id, ErrorResponse::from(Box::new(e))) + { Ok(_) => info!("Error response for {} accepted by Runtime API", request_id), Err(e) => { error!("Unable to send error response for {} to Runtime API: {}", request_id, e); @@ -243,7 +246,7 @@ where "Error for {} is not recoverable, sending fail_init signal and panicking", request_id ); - self.runtime_client.fail_init(ErrorResponse::from(Box::from(e))); + self.runtime_client.fail_init(ErrorResponse::from(Box::new(e))); panic!("Could not send error response"); } } @@ -271,11 +274,11 @@ where match err.request_id.clone() { Some(req_id) => { self.runtime_client - .event_error(&req_id, ErrorResponse::from(Box::from(err))) + .event_error(&req_id, ErrorResponse::from(Box::new(err))) .expect("Could not send event error response"); } None => { - self.runtime_client.fail_init(ErrorResponse::from(Box::from(err))); + self.runtime_client.fail_init(ErrorResponse::from(Box::new(err))); } } @@ -355,7 +358,7 @@ pub(crate) mod tests { "Handler threw an unexpected error: {}", output.err().unwrap() ); - let output_string = output.unwrap(); + let output_string = output.ok().unwrap(); assert_eq!(output_string, "hello", "Unexpected output message: {}", output_string); } } From 0bce533f72dda9d13bf039d783c1dc3ae711c558 Mon Sep 17 00:00:00 2001 From: sapessi Date: Tue, 4 Dec 2018 09:47:45 -0800 Subject: [PATCH 12/14] Addressed code review changes --- Cargo.lock | 1 - lambda-runtime/Cargo.toml | 3 +-- lambda-runtime/examples/basic.rs | 2 +- lambda-runtime/examples/custom_error_failure.rs | 5 +++-- lambda-runtime/src/lib.rs | 8 +++----- 5 files changed, 8 insertions(+), 11 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4a6e4ae1..7c3ed972 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -412,7 +412,6 @@ dependencies = [ "backtrace 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "failure_derive 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "hyper 0.12.12 (registry+https://github.com/rust-lang/crates.io-index)", "hyper-tls 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "lambda_runtime_client 0.1.0", diff --git a/lambda-runtime/Cargo.toml b/lambda-runtime/Cargo.toml index 59167d47..d2fb6e72 100644 --- a/lambda-runtime/Cargo.toml +++ b/lambda-runtime/Cargo.toml @@ -25,6 +25,5 @@ simple_logger = "^1" hyper-tls = "^0.3" simple-error = "^0.1" failure = "^0.1" -failure_derive = "^0.1" rusoto_core = "^0.35" -rusoto_dynamodb = "^0.35" +rusoto_dynamodb = "^0.35" \ No newline at end of file diff --git a/lambda-runtime/examples/basic.rs b/lambda-runtime/examples/basic.rs index 879a5675..c1fbc29f 100644 --- a/lambda-runtime/examples/basic.rs +++ b/lambda-runtime/examples/basic.rs @@ -1,13 +1,13 @@ extern crate lambda_runtime as lambda; extern crate log; extern crate serde_derive; -#[macro_use] extern crate simple_error; extern crate simple_logger; use lambda::{lambda, HandlerError}; use log::error; use serde_derive::{Deserialize, Serialize}; +use simple_error::bail; use std::error::Error; #[derive(Deserialize)] diff --git a/lambda-runtime/examples/custom_error_failure.rs b/lambda-runtime/examples/custom_error_failure.rs index f9bfa164..fa6c01bf 100644 --- a/lambda-runtime/examples/custom_error_failure.rs +++ b/lambda-runtime/examples/custom_error_failure.rs @@ -1,10 +1,11 @@ +#![feature(custom_attribute)] +extern crate failure; extern crate lambda_runtime as lambda; extern crate log; extern crate serde_derive; extern crate simple_logger; -#[macro_use] -extern crate failure; +use failure::Fail; use lambda::{lambda, HandlerError}; use log::error; use serde_derive::{Deserialize, Serialize}; diff --git a/lambda-runtime/src/lib.rs b/lambda-runtime/src/lib.rs index beeb291e..3b776f7c 100644 --- a/lambda-runtime/src/lib.rs +++ b/lambda-runtime/src/lib.rs @@ -7,15 +7,13 @@ //! package must be called `bootstrap`. //! //! ```rust,no_run -//! #[macro_use] //! extern crate serde_derive; -//! #[macro_use] //! extern crate lambda_runtime; -//! #[macro_use] //! extern crate simple_error; //! -//! use lambda_runtime::HandlerError; -//! +//! use lambda_runtime::{HandlerError, lambda}; +//! use simple_error::bail; +//! use serde_derive::{Serialize, Deserialize}; //! //! #[derive(Deserialize, Clone)] //! struct CustomEvent { From bd3cb34b46a647c359f54ff723772b1653958744 Mon Sep 17 00:00:00 2001 From: sapessi Date: Tue, 4 Dec 2018 14:33:02 -0800 Subject: [PATCH 13/14] Changed error handling codes according to latest specs clarified in #23 --- lambda-runtime-client/src/client.rs | 4 ++-- lambda-runtime-client/src/error.rs | 19 +++++++++---------- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/lambda-runtime-client/src/client.rs b/lambda-runtime-client/src/client.rs index 0b89e990..30f1673e 100644 --- a/lambda-runtime-client/src/client.rs +++ b/lambda-runtime-client/src/client.rs @@ -1,4 +1,4 @@ -use error::{ApiError, ErrorResponse}; +use error::{ApiError, ErrorResponse, ERROR_TYPE_UNHANDLED}; use hyper::{ client::HttpConnector, header::{self, HeaderMap, HeaderValue}, @@ -352,7 +352,7 @@ impl RuntimeClient { header::CONTENT_TYPE, header::HeaderValue::from_static(API_ERROR_CONTENT_TYPE), ) - .header(RUNTIME_ERROR_HEADER, e.error_code) + .header(RUNTIME_ERROR_HEADER, HeaderValue::from_static(ERROR_TYPE_UNHANDLED)) .body(Body::from(body)) .unwrap() } diff --git a/lambda-runtime-client/src/error.rs b/lambda-runtime-client/src/error.rs index 422e6179..3a85bbb1 100644 --- a/lambda-runtime-client/src/error.rs +++ b/lambda-runtime-client/src/error.rs @@ -17,10 +17,14 @@ use serde_json; /// Error type description for the `ErrorResponse` event. This type should be returned /// for errors that were handled by the function code or framework. -pub const ERROR_TYPE_HANDLED: &str = "Handled"; +#[allow(dead_code)] +pub(crate) const ERROR_TYPE_HANDLED: &str = "Handled"; /// Error type description for the `ErrorResponse` event. This type is used for unhandled, /// unexpcted errors. -pub const ERROR_TYPE_UNHANDLED: &str = "Unhandled"; +pub(crate) const ERROR_TYPE_UNHANDLED: &str = "Unhandled"; +/// Error type for the error responses to the Runtime APIs. In the future, this library +/// should use a customer-generated error code +pub const RUNTIME_ERROR_TYPE: &str = "RustRuntimeError"; /// This object is used to generate requests to the Lambda Runtime APIs. /// It is used for both the error response APIs and fail init calls. @@ -28,10 +32,6 @@ pub const ERROR_TYPE_UNHANDLED: &str = "Unhandled"; /// this object to be compatible with the APIs. #[derive(Serialize)] pub struct ErrorResponse { - /// Internal error code to be sent to the Lambda Runtime APIs in the - /// `Lambda-Runtime-Function-Error-Type` header. - #[serde(skip)] - pub error_code: String, /// The error message generated by the application. #[serde(rename = "errorMessage")] pub error_message: String, @@ -59,11 +59,10 @@ impl ErrorResponse { /// /// # Return /// A new instance of the `ErrorResponse` object. - fn new(message: String, err_type: String, code: String) -> ErrorResponse { + fn new(message: String, err_type: String) -> ErrorResponse { let mut err = ErrorResponse { error_message: message, error_type: err_type, - error_code: code, stack_trace: Option::default(), }; let is_backtrace = env::var("RUST_BACKTRACE"); @@ -89,7 +88,7 @@ impl ErrorResponse { /// # Return /// A populated `RuntimeError` object that can be used with the Lambda Runtime API. pub fn handled(message: String) -> ErrorResponse { - ErrorResponse::new(message, ERROR_TYPE_HANDLED.to_owned(), "RuntimeError".to_owned()) + ErrorResponse::new(message, RUNTIME_ERROR_TYPE.to_owned()) } /// Creates a new `RuntimeError` object with the unhandled error type. @@ -101,7 +100,7 @@ impl ErrorResponse { /// # Return /// A populated `RuntimeError` object that can be used with the Lambda Runtime API. pub fn unhandled(message: String) -> ErrorResponse { - ErrorResponse::new(message, ERROR_TYPE_UNHANDLED.to_owned(), "RuntimeError".to_owned()) + ErrorResponse::new(message, RUNTIME_ERROR_TYPE.to_owned()) } } From 5b9bad9d7ab362f94a3fea233ad6d7062d280537 Mon Sep 17 00:00:00 2001 From: sapessi Date: Tue, 4 Dec 2018 14:33:39 -0800 Subject: [PATCH 14/14] Removed custom_attribute feature to fix build --- lambda-runtime/examples/custom_error_failure.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/lambda-runtime/examples/custom_error_failure.rs b/lambda-runtime/examples/custom_error_failure.rs index fa6c01bf..cfa9a47a 100644 --- a/lambda-runtime/examples/custom_error_failure.rs +++ b/lambda-runtime/examples/custom_error_failure.rs @@ -1,4 +1,3 @@ -#![feature(custom_attribute)] extern crate failure; extern crate lambda_runtime as lambda; extern crate log;