Skip to content
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

Initialize Servlets at construction - in the initialize() method #287

Closed
sapessi opened this issue Oct 1, 2019 · 10 comments · Fixed by #331
Closed

Initialize Servlets at construction - in the initialize() method #287

sapessi opened this issue Oct 1, 2019 · 10 comments · Fixed by #331
Assignees
Milestone

Comments

@sapessi
Copy link
Collaborator

sapessi commented Oct 1, 2019

Scenario

SpringLambdaContainerHandler only creates a new instance of DispatcherServlet in the initialize() method and registers it with the context. The filter chain will then call the servlet's init() method lazily when the servlet is actually needed. This causes the initialize() method of SpringLambdaContainerHandler to return very quickly, making the asynchronous initialization wrapper less useful.

Expected behavior

Initialize the Servlet during the container handler initialization. The servlet specs seem to leave this up to the implementation:

After the servlet object is instantiated, the container must initialize the servlet before
it can handle requests from clients.

@sapessi sapessi added this to the Release 1.5 milestone Oct 1, 2019
@sapessi sapessi self-assigned this Oct 1, 2019
@kartoffelsup
Copy link

I've (hackily and temporarily) implemented my own Async Initializer and noticed that the jvm startup also needs to be taken into account when calculating the maximum time to wait on the init.

This is called in the static block of my LambdaHandler:
07:16:16 2019-10-15 07:16:16 INFO AsyncHandlerInitializer:26 - Starting async init of handler on thread: Thread-1
And I let it wait for init for about ~7 seconds:
07:16:23 2019-10-15 07:16:23 INFO AsyncHandlerInitializer:46 - Returning from AsyncHandlerInitializer#init. Waited for: '7197ms'
But it says the init duration was 9+ seconds:
07:16:30 REPORT RequestId: asdf Duration: 6141.40 ms Billed Duration: 6200 ms Memory Size: 1600 MB Max Memory Used: 276 MB Init Duration: 9265.40 ms

It seems that at least 2 seconds are used for the jvm (or something else I do not see) to startup?

@sapessi
Copy link
Collaborator Author

sapessi commented Oct 15, 2019

@kartoffelsup the JVM start is pretty quick - enabling X-Ray on the function will give you a good idea of how long the JVM startup takes in the initialization step. However, the JVM may also be busy loading other classes before it gets to the initializer, that's where the time may be going (just guessing).

To address this, in my samples I take a measurement of the start time first, before the JVM gets to the heavier init instructions. Check out this springboot2 test.

@kartoffelsup
Copy link

@sapessi thanks, I've enabled X-Ray and it indeed seems to take around 1-3 seconds (varies a lot) for the JVM to start (probably because my archive is about 50mb). So it would be desirable if the grace period in AsyncInitializationWrapper could be configurable (otherwise I would have to manipulate the actual start time that is passed as constructor parameter)

@sapessi
Copy link
Collaborator Author

sapessi commented Oct 22, 2019

Thanks for the feedback @kartoffelsup - We'll certainly make it configurable in the next release. Let me also dig into any other options to account for that time automatically. I'll update this issue as I find out more.

@kartoffelsup
Copy link

It seems one can use ManagementFactory.getRuntimeMXBean().getStartTime(); to get the actual JVM start time. I'm using this now for my temp solution.

@sapessi
Copy link
Collaborator Author

sapessi commented Jan 7, 2020

Thanks a great find. Thanks for the update @kartoffelsup!

sapessi added a commit that referenced this issue Mar 31, 2020
…quests load on startup are initialized right away, as part of the initialization() method call in LambdaServletContainerHandler. Also centralized the lazy Servlet initialization to the ServletExecutionFilter so that we don't have code scattered all around. This begins to address #287
sapessi added a commit that referenced this issue Mar 31, 2020
…es the actual JVM start time to calculate the timeout milliseconds. Also added the new method to the builder object and deprecated the current method that receives a milliseconds epoch parameter. I'm not deprecating the constructor of the async initializer class that receives the parameter as it may still be useful for tests. This change was suggested in #287
@sapessi
Copy link
Collaborator Author

sapessi commented Mar 31, 2020

Hey @kartoffelsup I've made changes for both issues and committed them to the v1.5 branch. Would be great if you could test with 1.5-SNAPSHOT from the branch. You can take a look at the last two commits (they reference this issue)

@kartoffelsup
Copy link

Hi, thanks for the update. I'll try it out ASAP :)

@kartoffelsup
Copy link

kartoffelsup commented Apr 1, 2020

@sapessi Works great now, after increasing the initialization timeout:

SpringLambdaContainerHandler.getContainerConfig().setInitializationTimeout((int) TimeUnit.SECONDS.toMillis(20L));

Not sure if 10 seconds is a good default, since we are expecting it to take longer when using the async initializer?

@sapessi
Copy link
Collaborator Author

sapessi commented Apr 2, 2020

Fair @kartoffelsup - I'll look at increasing it to a sane default. Need to balance cost and not getting in the way.

@sapessi sapessi linked a pull request Apr 7, 2020 that will close this issue
sapessi added a commit that referenced this issue Apr 8, 2020
* Bump spring.version in /aws-serverless-java-container-spring (#319)

Bumps `spring.version` from 5.1.9.RELEASE to 5.2.3.RELEASE.

Updates `spring-webmvc` from 5.1.9.RELEASE to 5.2.3.RELEASE
- [Release notes](https://github.com/spring-projects/spring-framework/releases)
- [Commits](spring-projects/spring-framework@v5.1.9.RELEASE...v5.2.3.RELEASE)

Updates `spring-test` from 5.1.9.RELEASE to 5.2.3.RELEASE
- [Release notes](https://github.com/spring-projects/spring-framework/releases)
- [Commits](spring-projects/spring-framework@v5.1.9.RELEASE...v5.2.3.RELEASE)

Signed-off-by: dependabot[bot] <[email protected]>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Bump spring-webflux in /aws-serverless-java-container-springboot2 (#318)

Bumps [spring-webflux](https://github.com/spring-projects/spring-framework) from 5.1.9.RELEASE to 5.2.0.RELEASE.
- [Release notes](https://github.com/spring-projects/spring-framework/releases)
- [Commits](spring-projects/spring-framework@v5.1.9.RELEASE...v5.2.0.RELEASE)

Signed-off-by: dependabot[bot] <[email protected]>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* ci: Fixing Spring build to use 5.2 as latest

* chore(deps): Bump Spring 5.1 path release to address a security vulnerability

* chore(deps): Fixing usual spring dependency mess with exlusions out of the spring-security package used in the tests

* Fix for issue #317 (#323)

* fix issue 317 - use charset from request

* update dependencies

* update build dependencies, remove spring boot 2.0.x

* restoring ci config

Co-authored-by: Stefano Buliani <[email protected]>

* test: Fixed Spring security tests for SpringBoot 2, added validation tests and updated servlet tests to use the new servletApplication option

* fix: Avoid flushing the response buffer if we are dispatching the request asynchronously. This was causing race conditions in the SpringBoot 2 WebFlux implementation - requests that had to run through security or validation filters took longer and the library flushed an empty request, which caused the status code to default to 200. This fix addresses issues #279, #304, and #306

* chore(deps): Bump spring dependency version and added webmvc optional dependency to truly support Servlet-only server

* feat: New application type parameter to SpringBootLambdaContainerHandler that tells the framework whether to start a reactive or servlet-based embedded server. Also added a new servletApplication method to the builder object.

* test: Fixed UTF-8 encoding test

* ci: Fixed dependencies for CI run on SpringBoot 2

* ci: More Spring dependency convergence issues during CI

* fix: Added null-check on getServerName in case the multi-value headers property is null. Unlikely outside of tests but better safe than sorry. This addresses #327

* fix: Changed servlet initialization mechanism so that servlet that requests load on startup are initialized right away, as part of the initialization() method call in LambdaServletContainerHandler. Also centralized the lazy Servlet initialization to the ServletExecutionFilter so that we don't have code scattered all around. This begins to address #287

* feat: Added new 0-parameter constructor for async initializer that uses the actual JVM start time to calculate the timeout milliseconds. Also added the new method to the builder object and deprecated the current method that receives a milliseconds epoch parameter. I'm not deprecating the constructor of the async initializer class that receives the parameter as it may still be useful for tests. This change was suggested in #287

* fix: Updated SpringBoot 1.x handler to use the new servlet initialization mechanism

* ci: switch SpringBoot slow integration test to use a custom async time since the JVM is reused for both tests in the and we cannot reuse the actual JVM init time

* feat: New models for HTTP API support for #329

* feat: First implementation of HTTP API servlet request, request reader, and security context writer - continuing to address #329

* test: Basic unit tests for the new HTTP API support in core library (#329)

* feat: Updated log formatter to support both versions (1 and 2) of the proxy request model (#329)

* feat: Further generified request readers to read to a generic HttpServletRequest rather than specific implementations of it. This makes it easier to create container handler implementations that support HTTP API, API Gateway, and ALB (#329)

* test: Fixed tests for new logged and generified request readers

* feat: Added HTTP API support to Jersey implementation with new getHttpApiV2ProxyHandler method (#329)

* feat: Added HTTP API support to Spark implementation (#329)

* feat: Added HTTP API support to Spring implementation (#329)

* feat: HTTP API support in SpringBoot 2 implementation. bug: Fixed an issue with the implementation of AsyncContext where it wasn't dispatching if the handler wasn't set

* feat: First pass of HTTP API support in struts 2 implementation (#329)

* fix: Added support for HTTP APIs to the request dispatcher

* chore(deps): Dependency bump all around. Rotated Jersey ci versions

* fix: Updated stream handling logic to work with reactive applications as suggested in #316

* test: Added unit test to replicate #333

* feat: New configuration parameter to skip exception mapping and allow exception to bubble up from #307

* fix: Fixed spotbugs issue in RuntimeException cast

* test: Added tests for more complex content types mentioned in issue #315

* docs: Updated samples to support SAM CLI operations out of the box to address #293 and switched to HTTP API by default

* feat: Updated archetypes to work out of the box with the SAM CLI, continuing to address #293

* chore: License header pass on the entire project

* fix: Set default value for setDisableException mapper in config to false

* fix: Updated default initialization timeout to 20 seconds

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Eran Medan <[email protected]>
jogep pushed a commit to jogep/aws-serverless-java-container that referenced this issue Dec 8, 2020
…quests load on startup are initialized right away, as part of the initialization() method call in LambdaServletContainerHandler. Also centralized the lazy Servlet initialization to the ServletExecutionFilter so that we don't have code scattered all around. This begins to address aws#287
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants