Slow first call after restarting Spring Boot application
Quick update we followed @willermo's answer plus a couple of tips from another forum have led us in the right direction to fix the problem.
We logged the class loading using the -verbose:class
flag, which made it clear that the problem were classes being lazy loaded at the moment of the first call.
To pre-load these classes, we used an ApplicationRunner
to trigger the calls on application startup, as suggested by @willermo; this allowed us to deterministically warm up all the servers behind the load balancer with a single call for each.
There were a couple extra obstacles that were easy to fix:
- Adding the
ApplicationRunner
broke all our tests, so we had to exclude it from the test profile. - We did not want to persist the effects on the DB of these "fake" calls, so we wrapped them in a transaction that we rollback in the end.
This was our final solution:
@Component
@Profile("!test")
public class AppStartupRunner implements ApplicationRunner {
// [Constructor with injected dependencies]
@Transactional
@Override
public void run(ApplicationArguments args) throws Exception {
// [Make the calls]
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
}
}
You can try to make the warm up call using an application runner.
public interface ApplicationRunner
Interface used to indicate that a bean should run when it is contained within a SpringApplication. Multiple ApplicationRunner beans can be defined within the same application context and can be ordered using the Ordered interface or @Order annotation.
e.g.
@Component
public class AppStartupRunner implements ApplicationRunner {
@Override
public void run(ApplicationArguments args) throws Exception {
System.out.println("Running");
//Make the first call here
}
}
Application Runner