Skip to content

Commit c3dfd7b

Browse files
authored
Merge pull request awslabs#3 from awslabs/lifetime-cleanup
Remove RuntimeClient trait, simplify lifetimes in Runtime.
2 parents 54fd3e7 + 80e9c1a commit c3dfd7b

File tree

8 files changed

+57
-110
lines changed

8 files changed

+57
-110
lines changed

.rustfmt.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,2 @@
1-
reorder_imports = true
21
merge_imports = true
32
max_width = 120

lambda-runtime-client/src/client.rs

Lines changed: 22 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -44,47 +44,6 @@ impl fmt::Display for LambdaHeaders {
4444
}
4545
}
4646

47-
/// Trait that defines the methods that should be implemented by a Lambda Runtime API client.
48-
/// Events are returned as a `Vec<u8>` and output for the `event_response()` method should
49-
/// also be passed as a `Vec<u8>`. Serialization and deserialization are up to the runtime
50-
/// library. When returning an error to the `event_error()` or `fail_init()` methods the objects
51-
/// should implement the `error::RuntimeApiError` triat.
52-
pub trait RuntimeClient {
53-
/// Should fetch the next event from the Runtime APIs.
54-
///
55-
/// # Return
56-
/// A tuple of the event raw bytes and the `EventContext` object extracted from the
57-
/// Lambda Runtime API headers - see the `LambdaHeaders` enum.
58-
fn next_event(&self) -> Result<(Vec<u8>, EventContext), ApiError>;
59-
/// Should return the handler response to the Runtime APIs.
60-
///
61-
/// # Arguments
62-
///
63-
/// * `request_id` The original AWS request id received from the `poll_events()` method.
64-
/// * `output` The object returned by the handler serialized to its raw bytes representation
65-
/// as a `Vec<u8>`.
66-
///
67-
/// # Return
68-
/// A `Result<(), RuntimeError>` signifying the API call's success or failure.
69-
fn event_response(&self, request_id: &str, output: Vec<u8>) -> Result<(), ApiError>;
70-
/// Should send an error response to the Runtime APIs.
71-
///
72-
/// # Arguments
73-
///
74-
/// * `request_id` The original AWS request id received from the `poll_events()` method.
75-
/// * `e` The `errors::HandlerError` returned by the handler function.
76-
///
77-
/// # Return
78-
/// A `Result<(), RuntimeError>` signifying the API call's success or failure. A unit struct
79-
/// signifies a lack of an error.
80-
fn event_error(&self, request_id: &str, e: &RuntimeApiError) -> Result<(), ApiError>;
81-
/// Should tell the Runtime APIs that the custom runtime has failed to initialize and the
82-
/// execution environment should be terminated.
83-
fn fail_init(&self, e: &RuntimeApiError);
84-
/// Returns the endpoint this client is communicating with. Primarily used for debugging.
85-
fn get_endpoint(&self) -> String;
86-
}
87-
8847
/// AWS Moble SDK client properties
8948
#[derive(Deserialize, Clone)]
9049
pub struct ClientApplication {
@@ -148,25 +107,16 @@ pub struct EventContext {
148107
pub identity: Option<CognitoIdentity>,
149108
}
150109

151-
/// The client SDK for Lambda's Runtime APIs that implements the `RuntimeClient` trait.
152-
/// This object is used by the `RustRuntime` to communicate with the internal endpoint.
153-
pub struct HttpRuntimeClient {
110+
/// Used by the Runtime to communicate with the internal endpoint.
111+
pub struct RuntimeClient {
154112
_runtime: Runtime,
155113
http_client: Client<HttpConnector, Body>,
156114
endpoint: String,
157115
}
158116

159-
impl HttpRuntimeClient {
117+
impl RuntimeClient {
160118
/// Creates a new instance of the Runtime APIclient SDK. The http client has timeouts disabled and
161-
/// always send the `Connection: keep-alive` header.
162-
///
163-
/// # Arguments
164-
///
165-
/// * `http_endpoint` The http endpoint for the Runtime APIs. This value comes from the AWS_LAMBDA_RUNTIME_API
166-
/// environment variable.
167-
///
168-
/// # Return
169-
/// An instance of the Runtime APIs client SDK.
119+
/// will always send a `Connection: keep-alive` header.
170120
pub fn new(endpoint: String, runtime: Option<Runtime>) -> Result<Self, ApiError> {
171121
debug!("Starting new HttpRuntimeClient for {}", endpoint);
172122
// start a tokio core main event loop for hyper
@@ -177,20 +127,17 @@ impl HttpRuntimeClient {
177127

178128
let http_client = Client::builder().executor(runtime.executor()).build_http();
179129

180-
Ok(HttpRuntimeClient {
130+
Ok(RuntimeClient {
181131
_runtime: runtime,
182132
http_client,
183133
endpoint,
184134
})
185135
}
186136
}
187137

188-
impl RuntimeClient for HttpRuntimeClient {
189-
/// Makes the HTTP call to poll for new events to the Runtime APIs.
190-
///
191-
/// # Return
192-
/// A `Result` containing a tuple of the new event of type `E` and its `EventContext`.
193-
fn next_event(&self) -> Result<(Vec<u8>, EventContext), ApiError> {
138+
impl RuntimeClient {
139+
/// Polls for new events to the Runtime APIs.
140+
pub fn next_event(&self) -> Result<(Vec<u8>, EventContext), ApiError> {
194141
let uri = format!(
195142
"http://{}/{}/runtime/invocation/next",
196143
self.endpoint, RUNTIME_API_VERSION
@@ -252,7 +199,7 @@ impl RuntimeClient for HttpRuntimeClient {
252199
///
253200
/// # Returns
254201
/// A `Result` object containing a bool return value for the call or an `error::ApiError` instance.
255-
fn event_response(&self, request_id: &str, output: Vec<u8>) -> Result<(), ApiError> {
202+
pub fn event_response(&self, request_id: &str, output: Vec<u8>) -> Result<(), ApiError> {
256203
let uri: Uri = format!(
257204
"http://{}/{}/runtime/invocation/{}/response",
258205
self.endpoint, RUNTIME_API_VERSION, request_id
@@ -299,7 +246,7 @@ impl RuntimeClient for HttpRuntimeClient {
299246
///
300247
/// # Returns
301248
/// A `Result` object containing a bool return value for the call or an `error::ApiError` instance.
302-
fn event_error(&self, request_id: &str, e: &RuntimeApiError) -> Result<(), ApiError> {
249+
pub fn event_error(&self, request_id: &str, e: &RuntimeApiError) -> Result<(), ApiError> {
303250
let uri: Uri = format!(
304251
"http://{}/{}/runtime/invocation/{}/error",
305252
self.endpoint, RUNTIME_API_VERSION, request_id
@@ -346,30 +293,33 @@ impl RuntimeClient for HttpRuntimeClient {
346293
/// # Panics
347294
/// If it cannot send the init error. In this case we panic to force the runtime
348295
/// to restart.
349-
fn fail_init(&self, e: &RuntimeApiError) {
296+
pub fn fail_init(&self, e: &RuntimeApiError) {
350297
let uri: Uri = format!("http://{}/{}/runtime/init/error", self.endpoint, RUNTIME_API_VERSION)
351298
.parse()
352-
.expect("Could not generate Runtime API URI");
299+
.expect("Could not generate Runtime URI");
353300
error!("Calling fail_init Runtime API: {}", e.to_response().error_message);
354301
let err_body = serde_json::to_vec(&e.to_response()).expect("Could not serialize error object");
355302
let req = self.get_runtime_post_request(&uri, err_body);
356303

357-
match self.http_client.request(req).wait() {
358-
Ok(_) => {}
359-
Err(e) => {
304+
let resp = self
305+
.http_client
306+
.request(req)
307+
.map_err(|e| {
360308
error!("Error while sending init failed message: {}", e);
361309
panic!("Error while sending init failed message: {}", e);
362-
}
363-
}
310+
}).map(|resp| {
311+
info!("Successfully sent error response to the runtime API: {:?}", resp);
312+
});
313+
tokio::spawn(resp);
364314
}
365315

366316
/// Returns the endpoint configured for this HTTP Runtime client.
367-
fn get_endpoint(&self) -> String {
317+
pub fn get_endpoint(&self) -> String {
368318
self.endpoint.clone()
369319
}
370320
}
371321

372-
impl HttpRuntimeClient {
322+
impl RuntimeClient {
373323
/// Creates a Hyper `Request` object for the given `Uri` and `Body`. Sets the
374324
/// HTTP method to `POST` and the `Content-Type` header value to `application/json`.
375325
///

lambda-runtime-client/src/lib.rs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
#![warn(missing_docs)]
22
//! Rust client SDK for the AWS Lambda Runtime APIs. This crate defines
3-
//! both a `RuntimeClient` trait and it's implementation: `HttpRuntimeClient`.
4-
//! The `HttpRuntimeClient` object exposes all of the methods available in
5-
//! AWS Lambda's Runtime APIs and it can be used to build any rust-related
6-
//! custom runtime in Lambda.
3+
//! a `RuntimeClient` that encapsulates interactions with AWS Lambda's Runtime
4+
//! APIs.
75
//!
86
//! To return errors to the Runtime APIs through the `event_error()` or
97
//! `fail_init()` methods the `Error` objects must implement the `error::RuntimeApiError`
@@ -33,7 +31,7 @@
3331
//!
3432
//! fn main() {
3533
//! let runtime_endpoint = String::from("http://localhost:8080");
36-
//! let client: &RuntimeClient = &HttpRuntimeClient::new(runtime_endpoint, None)
34+
//! let client = RuntimeClient::new(runtime_endpoint, None)
3735
//! .expect("Could not initialize client");
3836
//!
3937
//! let (event_data, event_context) = client.next_event()

lambda-runtime/examples/basic.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
extern crate lambda_runtime as lambda;
2-
extern crate serde_derive;
32
extern crate log;
3+
extern crate serde_derive;
44
extern crate simple_logger;
55

6-
use serde_derive::{Serialize, Deserialize};
7-
use lambda::{lambda, error::HandlerError};
6+
use lambda::{error::HandlerError, lambda};
87
use log::error;
8+
use serde_derive::{Deserialize, Serialize};
99
use std::error::Error;
1010

1111
#[derive(Deserialize)]

lambda-runtime/examples/with_custom_runtime.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
extern crate lambda_runtime as lambda;
2-
extern crate serde_derive;
32
extern crate log;
3+
extern crate serde_derive;
44
extern crate simple_logger;
55
extern crate tokio;
66

7-
use lambda::{lambda, error::HandlerError};
8-
use tokio::runtime::Runtime;
9-
use serde_derive::{Serialize, Deserialize};
7+
use lambda::{error::HandlerError, lambda};
108
use log::error;
9+
use serde_derive::{Deserialize, Serialize};
1110
use std::error::Error;
11+
use tokio::runtime::Runtime;
1212

1313
#[derive(Deserialize, Clone)]
1414
struct CustomEvent {

lambda-runtime/src/env.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,12 @@ pub trait ConfigProvider {
3939
/// used by the `start()` method of this module.
4040
pub struct EnvConfigProvider;
4141

42+
impl EnvConfigProvider {
43+
pub fn new() -> Self {
44+
EnvConfigProvider {}
45+
}
46+
}
47+
4248
impl ConfigProvider for EnvConfigProvider {
4349
/// Loads the function settings from the Lambda environment variables:
4450
/// https://docs.aws.amazon.com/lambda/latest/dg/current-supported-versions.html

lambda-runtime/src/runtime.rs

Lines changed: 18 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
use std::{error::Error, result};
22

3-
use lambda_runtime_client;
43
use serde;
54
use serde_json;
65

76
use context::Context;
87
use env::{ConfigProvider, EnvConfigProvider, FunctionSettings};
98
use error::{HandlerError, RuntimeError};
9+
use lambda_runtime_client::RuntimeClient;
1010
use tokio::runtime::Runtime as TokioRuntime;
1111

1212
const MAX_RETRIES: i8 = 3;
@@ -22,12 +22,12 @@ pub type Handler<E, O> = fn(E, Context) -> Result<O, HandlerError>;
2222
///
2323
/// # Panics
2424
/// The function panics if the Lambda environment variables are not set.
25-
pub fn start<E: 'static, O: 'static>(f: Handler<E, O>, runtime: Option<TokioRuntime>)
25+
pub fn start<E, O>(f: Handler<E, O>, runtime: Option<TokioRuntime>)
2626
where
2727
for<'invocation> E: serde::Deserialize<'invocation>,
2828
O: serde::Serialize,
2929
{
30-
start_with_config(f, &EnvConfigProvider {}, runtime)
30+
start_with_config(f, EnvConfigProvider::new(), runtime)
3131
}
3232

3333
#[macro_export]
@@ -53,13 +53,11 @@ macro_rules! lambda {
5353
/// The function panics if the `ConfigProvider` returns an error from the `get_runtime_api_endpoint()`
5454
/// or `get_function_settings()` methods. The panic forces AWS Lambda to terminate the environment
5555
/// and spin up a new one for the next invocation.
56-
pub(crate) fn start_with_config<E: 'static, O: 'static>(
57-
f: Handler<E, O>,
58-
config: &'static ConfigProvider,
59-
runtime: Option<TokioRuntime>,
60-
) where
56+
pub(crate) fn start_with_config<E, O, C>(f: Handler<E, O>, config: C, runtime: Option<TokioRuntime>)
57+
where
6158
for<'invocation> E: serde::Deserialize<'invocation>,
6259
O: serde::Serialize,
60+
C: ConfigProvider,
6361
{
6462
// if we cannot find the endpoint we panic, nothing else we can do.
6563
let endpoint: String;
@@ -81,10 +79,9 @@ pub(crate) fn start_with_config<E: 'static, O: 'static>(
8179
}
8280
}
8381

84-
match lambda_runtime_client::HttpRuntimeClient::new(endpoint, runtime) {
82+
match RuntimeClient::new(endpoint, runtime) {
8583
Ok(client) => {
86-
let trait_client: &lambda_runtime_client::RuntimeClient = &client;
87-
start_with_runtime_client(f, function_config, trait_client);
84+
start_with_runtime_client(f, function_config, client);
8885
}
8986
Err(e) => {
9087
panic!("Could not create runtime client SDK: {}", e);
@@ -103,11 +100,8 @@ pub(crate) fn start_with_config<E: 'static, O: 'static>(
103100
///
104101
/// # Panics
105102
/// The function panics if we cannot instantiate a new `RustRuntime` object.
106-
pub(crate) fn start_with_runtime_client<'env, E: 'static, O: 'static>(
107-
f: Handler<E, O>,
108-
func_settings: FunctionSettings,
109-
client: &'env lambda_runtime_client::RuntimeClient,
110-
) where
103+
pub(crate) fn start_with_runtime_client<E, O>(f: Handler<E, O>, func_settings: FunctionSettings, client: RuntimeClient)
104+
where
111105
for<'invocation> E: serde::Deserialize<'invocation>,
112106
O: serde::Serialize,
113107
{
@@ -125,15 +119,15 @@ pub(crate) fn start_with_runtime_client<'env, E: 'static, O: 'static>(
125119

126120
/// Internal representation of the runtime object that polls for events and communicates
127121
/// with the Runtime APIs
128-
pub(super) struct Runtime<'env, E: 'static, O: 'static> {
129-
runtime_client: &'env lambda_runtime_client::RuntimeClient,
122+
pub(super) struct Runtime<E, O> {
123+
runtime_client: RuntimeClient,
130124
handler: Handler<E, O>,
131125
max_retries: i8,
132126
settings: FunctionSettings,
133127
}
134128

135129
// generic methods implementation
136-
impl<'env, E, O> Runtime<'env, E, O> {
130+
impl<E, O> Runtime<E, O> {
137131
/// Creates a new instance of the `Runtime` object populated with the environment
138132
/// settings.
139133
///
@@ -151,8 +145,8 @@ impl<'env, E, O> Runtime<'env, E, O> {
151145
f: Handler<E, O>,
152146
config: FunctionSettings,
153147
retries: i8,
154-
client: &'env lambda_runtime_client::RuntimeClient,
155-
) -> result::Result<Runtime<'env, E, O>, RuntimeError> {
148+
client: RuntimeClient,
149+
) -> result::Result<Runtime<E, O>, RuntimeError> {
156150
debug!(
157151
"Creating new runtime with {} max retries for endpoint {}",
158152
retries,
@@ -169,7 +163,7 @@ impl<'env, E, O> Runtime<'env, E, O> {
169163

170164
// implementation of methods that require the Event and Output types
171165
// to be compatible with `serde`'s Deserialize/Serialize.
172-
impl<'env, E, O> Runtime<'env, E, O>
166+
impl<'env, E, O> Runtime<E, O>
173167
where
174168
for<'de> E: serde::Deserialize<'de>,
175169
O: serde::Serialize,
@@ -300,12 +294,12 @@ pub(crate) mod tests {
300294
use super::*;
301295
use context;
302296
use env;
303-
use lambda_runtime_client as cli;
297+
use lambda_runtime_client::RuntimeClient;
304298

305299
#[test]
306300
fn runtime_invokes_handler() {
307301
let config: &env::ConfigProvider = &env::tests::MockConfigProvider { error: false };
308-
let client: &lambda_runtime_client::RuntimeClient = &cli::HttpRuntimeClient::new(
302+
let client = RuntimeClient::new(
309303
config
310304
.get_runtime_api_endpoint()
311305
.expect("Could not get runtime endpoint"),

lambda-runtime/tests/skeptic.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
include!(concat!(env!("OUT_DIR"), "/skeptic-tests.rs"));
1+
include!(concat!(env!("OUT_DIR"), "/skeptic-tests.rs"));

0 commit comments

Comments
 (0)