You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I have an expensive task that should not be part of the handler. As that would be running the code again and again for each event call. According to AWS documentation the execution context is the place where these "global" code needs to go so that the output of the code is persistent over events. The docs say that "A new instance of the Context object is passed to each handler invocation". Is there a way create a custom context which saves the global state of the object between calls?
expensive task that should not be part of the handler
A bit of background on Lambda contexts. Each invocation of a Lambda function is provided a new context value which captures a set of introspective information about the function and optionally calling context information thats consistent across all types of event trigger. You can find documentation of how the Rust runtime represents that here. It's typically not a place to store user data because you'll get a new copy on each invocation as a function argument with new information.
Globals in Lambda are often used specifically as an optimization for cached initialization.
An example may be a function that requires a tokio Runtime in function code. Rather than recreate a new Runtime on every Lambda invocation which can be expensive, you might store a single Runtime in a thread local and share via RefCell to reduce the cost of initializing a new one on each . Here's a rough sketch for what that might look like.
Another option which I haven't myself explored but I think would be interesting is to implement the Handler trait for a custom struct that captures what you may store in global state within its struct fields. Typically you'll be using closures or fn defs to implement your lambda which already have implementations for Handler trait but that doesn't stop you from implementing Handler for your own struct.
Below is a rough sketch for what that might look like
I was wondering if an example for the current Handler interface could be provided in the context of http. I'm having a tricky time understanding how it should be declared. Thanks for any help. Here's the type I'm referring to:
/// Functions serving as ALB and API Gateway REST and HTTP API handlers must conform to this type.////// This can be viewed as a `lambda::Handler` constrained to `http` crate `Request` and `Response` typespubtraitHandler:Sized{/// The type of Error that this Handler will returntypeError;/// The type of Response this Handler will returntypeResponse:IntoResponse;/// The type of Future this Handler will returntypeFut:Future<Output = Result<Self::Response,Self::Error>> + 'static;/// Function used to execute handler behaviorfncall(&mutself,event:Request,context:Context) -> Self::Fut;}
19 | type Fut = dyn Future<Output = Result<Self::Response, Self::Error>> + 'static;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
...and I'm trying to fathom exactly what of those types doesn't have a known size.
Also, is there any specific reason why you are creating a separate handler function rather than just using the call function in your MyHandlerFn struct?
By the way, I've just added this example using a struct that implements the Handler trait for reference.
Activity
softprops commentedon Jun 12, 2019
A bit of background on Lambda contexts. Each invocation of a Lambda function is provided a new context value which captures a set of introspective information about the function and optionally calling context information thats consistent across all types of event trigger. You can find documentation of how the Rust runtime represents that here. It's typically not a place to store user data because you'll get a new copy on each invocation as a function argument with new information.
Globals in Lambda are often used specifically as an optimization for cached initialization.
An example may be a function that requires a tokio Runtime in function code. Rather than recreate a new Runtime on every Lambda invocation which can be expensive, you might store a single Runtime in a thread local and share via RefCell to reduce the cost of initializing a new one on each . Here's a rough sketch for what that might look like.
https://docs.rs/lazy_static/1.3.0/lazy_static/ is another crate that you may find helpful.
Another option which I haven't myself explored but I think would be interesting is to implement the Handler trait for a custom struct that captures what you may store in global state within its struct fields. Typically you'll be using closures or fn defs to implement your lambda which already have implementations for
Handlertrait but that doesn't stop you from implementingHandlerfor your own struct.Below is a rough sketch for what that might look like
arahalevich-move commentedon Jun 14, 2019
Thank you @softprops for the overview, last option looks pretty neat!
softprops commentedon Jun 14, 2019
I haven't tried it myself you so I'd be curious to hear how that goes for you
stacygrace commentedon Mar 22, 2020
I gave the last option a try and its working pretty great for me.
Don't have any code that I can share just yet but I'll try to put up a demo repo to link to soon. Thank you @softprops for that idea!
huntc commentedon Dec 2, 2020
I was wondering if an example for the current
Handlerinterface could be provided in the context of http. I'm having a tricky time understanding how it should be declared. Thanks for any help. Here's the type I'm referring to:My attempt so far:
...results in:
...and I'm trying to fathom exactly what of those types doesn't have a known size.
softprops commentedon Dec 3, 2020
I'm not sure if this is exactly what you mean but here's an example of an impl for a Fn type
I think
dynobjects themselves don't have a knowable size at compile time unless you wrap them in aBoxhuntc commentedon Dec 5, 2020
Thanks for the response. That code sample you provided is what I based my code on. Thanks for reminding about the use of box here too.
I think it’s clear that AWS lambda needs to at least provide a hook, or a great example of code initialisation for Rust.
Even better, folding over state with a scan-style function would be great, but perhaps that’s another issue. :-)
leo-suspensify commentedon May 2, 2021
The library has changed a little since this question was first asked, but it does work with BoxFuture as follows:
If this is the recommended solution then I can add it to the README
Jacco commentedon Dec 15, 2021
Am trying to do it a bit differently, and am struggling with lifetime management:
And then the following:
But I get
life mismatchandone type is more general than the othererrors on the line whererunis called.Anybody know how to resolve this?
nmoutschen commentedon Dec 17, 2021
Hey @Jacco !
Could you paste the entire error message?
Also, is there any specific reason why you are creating a separate handler function rather than just using the
callfunction in yourMyHandlerFnstruct?By the way, I've just added this example using a struct that implements the Handler trait for reference.