Skip to content

Refactor init #24

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from
Closed

Refactor init #24

wants to merge 2 commits into from

Conversation

tomerd
Copy link
Contributor

@tomerd tomerd commented Mar 9, 2020

No description provided.

@tomerd
Copy link
Contributor Author

tomerd commented Mar 9, 2020

needs #23

@tomerd tomerd requested a review from fabianfett March 9, 2020 02:30
@tomerd
Copy link
Contributor Author

tomerd commented Mar 9, 2020

@fabianfett we discussed the topic in #11. this API change bring two things:

  1. users can provide a LambdaHandler with a throwing init(eventLoop: EventLoop) ctor, which could be then used to initialize things like db-drivers, async-http-client etc. The lambda can then be run with Lambda.run(MyLambda.init)

  2. users can implement an optional bootstrap method via the BootstrappedLambdaHandler protocol for lambdas that need to once-only-action like preloading data from some remote source.

error in either of these will report an initialization error to the lambda runtime engine

@tomerd tomerd requested a review from glbrntt March 9, 2020 02:38
@tomerd
Copy link
Contributor Author

tomerd commented Mar 9, 2020

cc @glbrntt as you implemented the original init logic

@@ -31,14 +32,26 @@ extension Lambda {
self.run(handler as LambdaHandler)
}

/// Run a Lambda defined by implementing the `LambdaCodableHandler` protocol, having `In` and `Out` are `Decodable` and `Encodable` respectively.
///
/// - note: This is a blocking operation that will run forever, as it's lifecycle is managed by the AWS Lambda Runtime Engine.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo: it's -> its (and elsewhere)

Copy link
Contributor Author

@tomerd tomerd Mar 9, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will address in a following PR as we are about to refactor these APIs

@glbrntt
Copy link
Contributor

glbrntt commented Mar 9, 2020

  1. users can provide a LambdaHandler with a throwing init(eventLoop: EventLoop) ctor, which could be then used to initialize things like db-drivers, async-http-client etc. The lambda can then be run with Lambda.run(MyLambda.init)

@tomerd why did you go for a provider over the init you described here? So you don't force users to have an event loop?

Copy link
Member

@fabianfett fabianfett left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, long story short, I like the LambdaHandlerProvider idea a lot. So much, that I would keep it as the single solution and change it to:

public typealias LambdaHandlerProvider = (EventLoopGroup, EventLoopPromise<LambdaHandler>)

If we have this we don't need extra bootstrap callbacks:

  • all preparation work can be done in the provider
  • bootup error are reported
  • developers get access to the EventLoopGroup
  • the handler struct can have lets for everything needed.

Of course we can derive easier to use, potentially blocking, APIs from this. But as we have the LambdaHandler as the source of truth this should be the bootup source of truth ;)

@@ -298,18 +330,17 @@ public typealias LambdaInitResult = Result<Void, Error>
/// A callback to provide the result of Lambda initialization.
public typealias LambdaInitCallBack = (LambdaInitResult) -> Void

public typealias LambdaHandlerProvider = (EventLoop) throws -> LambdaHandler
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like this a lot! What do you think about making this:

  • async with a promise?
  • providing the EventLoopGroup? As I stated before: with more than 1700mb of ram one get's access to two cores, and I would really like to use both 😉
  • I think, if we make this async we don't need the bootstrap callback, and we can all call it a day? With this we have one callback that initialises a struct where we can set all properties.

Copy link
Contributor Author

@tomerd tomerd Mar 9, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks @fabianfett

async with a promise?
I think, if we make this async we don't need the bootstrap callback, and we can all call it a day? With this we have one callback that initialises a struct where we can set all properties.

the idea of separating this into a init (provider) and a bootstrap phases, is that we can make the provider blocking+throwing and the bootstrap async. this means you can do things like Lambda.run(MyLambda.init) in which you initialize some database/http client with the event loop that will run the lambda but dont have to worry calling a callback or completing a promise. we could change the provider API to also take a callback/promise and then create invariants of the user facing API that call-the-callback/complete-the-promise on the user's behalf to keep the user facing API simpler. I will play with that idea and post another version if it turns out okay

providing the EventLoopGroup? As I stated before: with more than 1700mb of ram one get's access to two cores, and I would really like to use both 😉

interesting point. the goal for exposing the underlying eventLoop to the be able to share it with a database/http client (for example) that also uses swift-nio. further, the eventLoopGroup we are using in the library only has 1 thread, since it optimizing for the lambda runtime use case and ensuring 1 thread is good for nio's performance. of course, the user can always create their own EventLoopGroup and use that if they want to do things in parallel.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@fabianfett @glbrntt here is the other alternative: #28

it works but a bit complicated to reason about so not sure which I prefer

@tomerd
Copy link
Contributor Author

tomerd commented Mar 9, 2020

@tomerd why did you go for a provider over the init you described here? So you don't force users to have an event loop?

@glbrntt an init that takes an EventLoop (ie init(eventLoop: EventLoop) == LambdaHandlerProvider signature, so this should work as described unless I am missing something?

@glbrntt
Copy link
Contributor

glbrntt commented Mar 9, 2020

@tomerd why did you go for a provider over the init you described here? So you don't force users to have an event loop?

@glbrntt an init that takes an EventLoop (ie init(eventLoop: EventLoop) == LambdaHandlerProvider signature, so this should work as described unless I am missing something?

Ah, I misinterpreted it: thought you meant the init was part of the LambdaHandler protocol.

tomerd added 2 commits March 9, 2020 19:49
motivation: make initialization logic more robust, allowing setup at contructor time and also async bootstrap

changes:
* break apart "initialization" into two parts:
  * optional throwing constructor (provider) that takes an EventLoop
  * optional BootstrappedLambdaHandler protocol that takes an EventLoop and returns async
* update core API and logic to support new initialization logic
* add tests to various initialization flows
@tomerd tomerd mentioned this pull request Mar 10, 2020
@tomerd
Copy link
Contributor Author

tomerd commented Mar 10, 2020

replaced with #28

@tomerd tomerd closed this Mar 10, 2020
@tomerd tomerd deleted the refactor-init branch March 10, 2020 18:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants