diff --git a/Cargo.lock b/Cargo.lock
index 2bb0f9f3..7c3ed972 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -411,6 +411,7 @@ 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)",
"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 +421,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 +911,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 +1384,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-client/src/client.rs b/lambda-runtime-client/src/client.rs
index 95471dc2..30f1673e 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, ERROR_TYPE_UNHANDLED};
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())
@@ -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, 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 5a2bc573..3a85bbb1 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};
@@ -10,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 = "Handled";
+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.
@@ -36,6 +47,38 @@ 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) -> ErrorResponse {
+ let mut err = ErrorResponse {
+ error_message: message,
+ error_type: err_type,
+ 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 +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 {
- error_message: message,
- error_type: String::from(ERROR_TYPE_HANDLED),
- stack_trace: Option::default(),
- }
+ ErrorResponse::new(message, RUNTIME_ERROR_TYPE.to_owned())
}
/// Creates a new `RuntimeError` object with the unhandled error type.
@@ -61,33 +100,20 @@ 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, RUNTIME_ERROR_TYPE.to_owned())
}
}
-/// 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(format!("{}", e))
+ }
}
/// Represents an error generated by the Lambda Runtime API client.
#[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.
@@ -96,16 +122,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,
}
}
@@ -134,6 +152,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 {
@@ -170,14 +190,3 @@ impl From for ApiError {
ApiError::new(e.description())
}
}
-
-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);
-
- err
- }
-}
diff --git a/lambda-runtime/Cargo.toml b/lambda-runtime/Cargo.toml
index 5acd7778..d2fb6e72 100644
--- a/lambda-runtime/Cargo.toml
+++ b/lambda-runtime/Cargo.toml
@@ -23,5 +23,7 @@ simple_logger = "^1"
[dev-dependencies]
hyper-tls = "^0.3"
+simple-error = "^0.1"
+failure = "^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 83736a45..c1fbc29f 100644
--- a/lambda-runtime/examples/basic.rs
+++ b/lambda-runtime/examples/basic.rs
@@ -1,11 +1,13 @@
extern crate lambda_runtime as lambda;
extern crate log;
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 simple_error::bail;
use std::error::Error;
#[derive(Deserialize)]
@@ -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..d9e18783
--- /dev/null
+++ b/lambda-runtime/examples/custom_error.rs
@@ -0,0 +1,66 @@
+extern crate lambda_runtime as lambda;
+extern crate log;
+extern crate serde_derive;
+extern crate simple_logger;
+
+use lambda::{lambda, HandlerError};
+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(),
+ }
+ }
+}
+
+#[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").into());
+ }
+
+ // 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..cfa9a47a
--- /dev/null
+++ b/lambda-runtime/examples/custom_error_failure.rs
@@ -0,0 +1,47 @@
+extern crate failure;
+extern crate lambda_runtime as lambda;
+extern crate log;
+extern crate serde_derive;
+extern crate simple_logger;
+
+use failure::Fail;
+use lambda::{lambda, HandlerError};
+use log::error;
+use serde_derive::{Deserialize, Serialize};
+use std::error::Error as StdError;
+
+#[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 {}).into());
+ }
+
+ 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..666f56ec 100644
--- a/lambda-runtime/examples/with_custom_runtime.rs
+++ b/lambda-runtime/examples/with_custom_runtime.rs
@@ -2,9 +2,11 @@ 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};
+use lambda::{lambda, HandlerError};
use log::error;
use serde_derive::{Deserialize, Serialize};
use std::error::Error;
@@ -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 {
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..ebbcd504 100644
--- a/lambda-runtime/src/error.rs
+++ b/lambda-runtime/src/error.rs
@@ -1,11 +1,35 @@
//! 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 backtrace;
-use lambda_runtime_client::error;
+use lambda_runtime_client::error::ApiError;
use serde_json;
+/// 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
/// is primarily used by other methods within this crate and should not be relevant
@@ -14,7 +38,6 @@ use serde_json;
#[derive(Debug, Clone)]
pub struct RuntimeError {
msg: String,
- stack_trace: Option,
/// The request id that generated this error
pub(crate) request_id: Option,
/// Whether the error is recoverable or not.
@@ -49,33 +72,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),
- stack_trace: 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 fmt::Display for RuntimeError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.msg)
@@ -106,66 +110,10 @@ 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
}
}
-
-/// 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/lib.rs b/lambda-runtime/src/lib.rs
index 36448d00..3b776f7c 100644
--- a/lambda-runtime/src/lib.rs
+++ b/lambda-runtime/src/lib.rs
@@ -7,13 +7,13 @@
//! package must be called `bootstrap`.
//!
//! ```rust,no_run
-//! #[macro_use]
//! extern crate serde_derive;
-//! #[macro_use]
//! extern crate lambda_runtime;
+//! extern crate simple_error;
//!
-//! use lambda_runtime::error::HandlerError;
-//!
+//! use lambda_runtime::{HandlerError, lambda};
+//! use simple_error::bail;
+//! use serde_derive::{Serialize, Deserialize};
//!
//! #[derive(Deserialize, Clone)]
//! struct CustomEvent {
@@ -32,7 +32,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),
@@ -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::*;
diff --git a/lambda-runtime/src/runtime.rs b/lambda-runtime/src/runtime.rs
index 770788f4..6b56a690 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::new(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::new(e)));
panic!("Failed to marshal handler output, panic");
}
}
@@ -235,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, &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);
@@ -244,7 +246,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::new(e)));
panic!("Could not send error response");
}
}
@@ -272,11 +274,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::new(err)))
.expect("Could not send event error response");
}
None => {
- self.runtime_client.fail_init(&err);
+ self.runtime_client.fail_init(ErrorResponse::from(Box::new(err)));
}
}
@@ -356,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);
}
}