Spring boot embedded tomcat application session does not invalidate - spring

Recently we ported our application from the web application running in tomcat to spring boot application with embedded tomcat.
After running the app for several days, memory and cpu usage have reached 100%.
In heap dump analysis it comes out that there was a bunch of http session objects which where not destroyed.
I can see in the debug that sessions created with configured timeout value, lets say, 5 minutes. But after this time the invalidation is not triggered. It invoked only if I do request again after the timeout period.
I have compared this behavior with app running in tomcat and I can see that session invalidation is triggered by ContainerBackgroungProcessor thread [StandardManager(ManagerBase).processExpires()]
I do not see this background thread in spring boot application.
What was done following some suggestions found:
session timeout set in application.properties:
server.session.timout=300
or in EmbeddedServletContainerCustomizer #Bean:
factory.setSessionTimout(5, TimeUnit.MINUTES)
Added HttpSessionEventPublisher and SessionRegistry beans
Nothing helps, sessions just not invalidated at the expiration time.
Some clue about this?

After some more debugging and documentation reading this is the reason and solution:
In tomcat, there is a thread spawned on behalf of the root container which scans periodically container and its child containers session pools and invalidates them. Each container/child container may be configured to have its own background processor to do the job or to rely on its host's background processor.
This controlled by context.backgroundProcessorDelay
Apache Tomcat 8 Configuration Reference
backgroundProcessorDelay -
This value represents the delay in seconds between the invocation of the backgroundProcess method on this engine and its child containers, including all hosts and contexts. Child containers will not be invoked if their delay value is not negative (which would mean they are using their own processing thread). Setting this to a positive value will cause a thread to be spawn. After waiting the specified amount of time, the thread will invoke the backgroundProcess method on this engine and all its child containers. If not specified, the default value for this attribute is 10, which represent a 10 seconds delay.
In spring boot application with embedded tomcat
there is TomcatEmbeddedServletContainerFactory.configureEngine() which sets this property -1 for the StandardEngine[Tomcat], which is the root container in tomcat hierarchy, as I understand.
All the child containers including web app also have this parameter set to -1.
And this means they all rely on someone else to do the job.
Spring do not do it, no-one do it.
The solution for me was to set this parameter for the app context:
#Bean
public EmbeddedServletContainerCustomizer servletContainerCustomizer() {
return new EmbeddedServletContainerCustomizer() {
#Override
public void customize(ConfigurableEmbeddedServletContainer container) {
if (container instanceof TomcatEmbeddedServletContainerFactory) {
TomcatEmbeddedServletContainerFactory factory = (TomcatEmbeddedServletContainerFactory) container;
TomcatContextCustomizer contextCustomizer = new TomcatContextCustomizer() {
#Override
public void customize(Context context) {
context.setBackgroundProcessorDelay(10);
}
};
List<TomcatContextCustomizer> contextCustomizers = new ArrayList<TomcatContextCustomizer>();
contextCustomizers.add(contextCustomizer);
factory.setTomcatContextCustomizers(contextCustomizers);
customizeTomcat(factory);
}
}

Related

How to restart springboot application from code

I have a springboot application with embedded tomcat. And on certain cases it should be restarted from code.
I have read several articles and SO posts regarding this,but yet to find a clean solution.
I am aware that 'context.close' , 'SpringApplication.exit(context)' exist and can be wrapped into something like this:
public static void restart() {
ApplicationArguments args = context.getBean(ApplicationArguments.class);
Thread thread = new Thread(() -> {
context.close();
context = SpringApplication.run(Application.class, args.getSourceArgs());
});
thread.setDaemon(false);
thread.start();
}
source: https://www.baeldung.com/java-restart-spring-boot-app
The problem is that using context.close() just doesn't work in a clean way. The context itself will be restarted though, but bunch of Threads will be left in the background (like Thread[pool-3-thread-1,5,main] Thread[Signal Dispatcher,9,system] Thread[OkHttp TaskRunner,5,main] ..etc).
And for every context restart these will be recreated, so the number of threads adds up gradually by each restart. Resulting in huge Thread mess as time passes.
Note1: A simple application exit by using 'context.close()' also wouldn't work because of these left over Threads. So the context close doesnt even close the application.
Note2: If I use System.exit(SpringApplication.exit(context)) I can kill the app gracefully, but can't restart it.
Note3: I don't want to use neither devtools nor actuator
So the question is how to perform a total restart for a springboot application?
You can use the RestartEndPoint in spring-cloud-context dependency to restart the Spring Boot application programmatically:
#Autowired
private RestartEndpoint restartEndpoint;
...
Thread restartThread = new Thread(() -> restartEndpoint.restart());
restartThread.setDaemon(false);
restartThread.start();

Readiness probe during Spring context startup

We are deploying our spring boot applications in OpenShift.
Currently we are trying to run a potentially long running task (database migration) before the webcontext is fully set up.
It is especially important that the app does not accept REST requests or process messages before the migration is fully run.
See the following minimal example:
// DemoApplication.java
#SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
// MigrationConfig.java
#Configuration
#Slf4j
public class MigrationConfig {
#PostConstruct
public void run() throws InterruptedException {
log.info("Migration...");
// long running task
Thread.sleep(10000);
log.info("...Migration");
}
}
// Controller.java
#RestController
public class Controller {
#GetMapping("/test")
public String test() {
return "test";
}
}
// MessageHandler.java
#EnableBinding(Sink.class)
public class MessageHandler {
#StreamListener(Sink.INPUT)
public void handle(String message) {
System.out.println("Received: " + message);
}
}
This works fine so far: the auto configuration class is processed before the app responds to requests.
What we are worried about, however, is OpenShifts readiness probe: currently we use an actuator health endpoint to check if the application is up and running.
If the migration takes a long time, OpenShift might stop the container, potentially leaving us with inconsistent state in the database.
Does anybody have an idea how we could communicate that the application is starting, but prevent REST controller or message handlers from running?
Edit
There are multiple ways of blocking incoming REST requests, #martin-frey suggested a servletfilter.
The larger problem for us is stream listener. We use Spring Cloud Stream to listen to a RabbitMQ queue.
I added an exemplary handler in the example above.
Do you have any suggestions on how to "pause" that?
What about a servletfilter that knows about the state of the migration? That way you should be able to handle any inbound request and return a responsecode to your liking. Also there would be no need to prevent any requesthandlers until the system is fully up.
I think it can run your app pod without influence if you set up good enough initialDelaySeconds for initialization of your application.[0][1]
readinessProbe:
httpGet:
path: /_status/healthz
port: 8080
initialDelaySeconds: 10120
timeoutSeconds: 3
periodSeconds: 30
failureThreshold: 100
successThreshold: 1
Additionally, I recommend to set up the liveness probes with same condition (but more time than the readiness probes' value), then you can implement automated recovery of your pods if the application is failed until initialDelaySeconds.
[0] [ https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/#define-readiness-probes ]
[1] [ https://docs.openshift.com/container-platform/latest/dev_guide/application_health.html ]
How about adding an init container which only role is the db migration stuffs without the application.
Then another container to serve the application. But be careful when deploying the application with more than 1 replica. The replicas will also execute the initcontainer at the same time if you are using Deployment.
If you need multiple replicas, you might want to consider StatefulSets instead.
Such database migrations are best handled by switching to a Recreate deployment strategy and doing the migration as a mid lifecyle hook. At that point there are no instances of your application running so it can be safely done. If you can't have downtime, then you need to have the application be able to be switched to some offline or read/only mode against a copy of your database while doing the migration.
Don't keep context busy doing a long task in PostConstruct. Instead start migration as fully asynchronous task and allow Spring to build the rest of the context meanwhile. At the end of the task just set some shared Future with success or failure. Wrap controller in a proxy (can be facilitated with AOP, for example) where every method except the health check tries to get value from the same future within a timeout. If it succeeds, migration is done, all calls are available. If not, reject the call. Your proxy would serve as a gate allowing to use only part of API that is critical to be available while migration is going on. The rest of it may simply respond with 503 indicating the service is not ready yet. Potentially those 503 responses can also be improved by measuring and averaging the time migration typically takes and returning this value with RETRY-AFTER header.
And with the MessageHandler you can do essentially same thing. You wait for result of the future in the handle method (provided message handlers are allowed to hang indefinitely). Once the result is set, it will proceed with message handling from that moment on.

What's the best way to close the Spring Applicationcontext?

There is two way to close the Spring ApplicationContext:
Solution 1:
ApplicationContext context = new ClassPathXmlApplicationContext(
"spring/application-context.xml");
// Application core ...
((AbstractApplicationContext) context).close();
Solution 2:
ApplicationContext context = new ClassPathXmlApplicationContext(
"spring/application-context.xml");
((AbstractApplicationContext) context).registerShutdownHook();
// Application core ...
What's the difference between this 2 solutions and what's the best in terms of performance ?
Solution 1 shuts down the application context
Solution 2 registers a callback, so spring will shut down, if the JVM is shut down, from javadoc :
Register a shutdown hook with the JVM runtime, closing this context on JVM shutdown unless it has already been closed at that time.
So both are two diffrent things, normally you will call registerShutdownHook() directly after you created the appication context. So when your user terminates the JVM, spring will be called and shuts itself down.
You should call close() when your application ends, to allow spring to destroy its beans.

Spring boot embedded jettty thread pool maximum size

I want to configure Thread pool size for my application which is using spring boot embedded jetty server. Below is the code snippet i am using.
I want to know what is the maximum thread pool size I can set for the embedded jetty server and is it the correct way of configuring it?
#Bean
public EmbeddedServletContainerFactory jettyConfigBean() {
JettyEmbeddedServletContainerFactory jef = new JettyEmbeddedServletContainerFactory();
jef.addServerCustomizers(new JettyServerCustomizer() {
public void customize(org.eclipse.jetty.server.Server server) {
final QueuedThreadPool threadPool = server.getBean(QueuedThreadPool.class);
server.setHandler(handlers);
}
});
return jef;
}
Speaking for spring-boot 2.0.0-SNAPSHOT:
This is for jetty and tomcat and undertow configurable via
server.jetty.acceptors
server.tomcat.max-connections
server.undertow.io-threads
See https://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/htmlsingle/#common-application-properties for a complete reference.
The maximum number of threads you can set is dependent on your machine, not so much on the hosting software. If you have a monster machine you can probably have hundreds of threads, whereas a regular laptop would probably only be able to handle tens of threads. You need to tune your configuration by testing. A good way is to setup a load test, for example see if 50 threads with 50 req/sec will crash your service, then check if increasing/decreasing the number of threads will help. You can find the limits of your application and machine with such a technique.
Regarding the correctness of the configuration, you can read this blog post which explains it very well: http://jdpgrailsdev.github.io/blog/2014/10/07/spring_boot_jetty_thread_pool.html
This is what you can do:
While working on newer versions, you need to create a server factory bean in a configuration file. I tested this on Spring Boot version 2.1.6 while the document I referred to is for version 2.3.3
#Bean
public ConfigurableServletWebServerFactory webServerFactory() {
JettyServletWebServerFactory factory = new JettyServletWebServerFactory();
factory.setPort(8080);
factory.setContextPath("/my-app");
QueuedThreadPool threadPool = new QueuedThreadPool();
threadPool.setMinThreads(10);
threadPool.setMaxThreads(100);
threadPool.setIdleTimeout(60000);
factory.setThreadPool(threadPool);
return factory;
}
Following is the link to Spring Docs: customizing-embedded-containers

Shutdown embedded Jetty in Spring-Boot Application with Apache CXF

In a Spring-Boot Application I register an Apache-CXF SOAP Service like this:
#Bean(destroyMethod = "destroy")
org.apache.cxf.endpoint.Server server(MyService myService) {
JaxWsServerFactoryBean svrFactory = new JaxWsServerFactoryBean();
svrFactory.setServiceClass(MyService.class);
svrFactory.setAddress("http://0.0.0.0:4711/MyService");
svrFactory.setServiceBean(myService);
svrFactory.getInInterceptors().add(new LoggingInInterceptor());
svrFactory.getOutInterceptors().add(new LoggingOutInterceptor());
return svrFactory.create();
}
It may happen at other places of my spring configuration, that the context can not be initialized succesfully (Application startup failed) and the application shutdown is initiated.
Unfortunately the sever bean, which is already created, stays alive and prevents the application from shutting down completely. I thought that destroyMethod = "destroy" would do the trick, but that only destroys the webapp/SOAP endpoint (resultig in HTTP ERROR 404) but the embedded jetty is still running.
Do I have any chance to configure the Spring Context in a way that prevents the embedded Jetty from staying alive when the Spring Context initialization failes at some point?

Resources