Is there any way to know the load time for a java application? - spring-boot

I am trying to compare performance of SpringBoot and Micronaut.
I have some applications implemented with both frameworks, and can get some info about JVM with Micrometer, but the information about the time each of these frameworks need to load from scratch and start working is something I am missing.
Is there any way to get it?
Thanks.

Spring boot logs startup time in format:
Started {applicationName} in {time} seconds (JVM running for {jvmTime})
e.g.
2019-05-18 20:50:07.099 INFO 6904 --- [ main] c.e.demo.DemoApplication : Started DemoApplication in 2.156 seconds (JVM running for 3.164)
If you want to have access to startup time programmatically in your application you can JVM running time on ApplicationStartedEvent:
#Component
public class StartupListener {
#EventListener
public void onStartup(ApplicationStartedEvent event) {
double startupTime = ManagementFactory.getRuntimeMXBean().getUptime() / 1000.0;
System.out.println("Application started in: " + startupTime);
}
}
Just to complete the answer with the Micronaut part:
#Singleton
#Requires(notEnv = Environment.TEST)
#Slf4j
public class InitialEventListener implements ApplicationEventListener<ServiceStartedEvent> {
#Getter
private long currentTimeMillis;
#Async
#Override
public void onApplicationEvent(ServiceStartedEvent event) {
currentTimeMillis = System.currentTimeMillis();
log.info("ServiceStartedEvent at " + currentTimeMillis + ":" + event);
}
}

Related

How to stop #CucumberContextConfiguration with #SpringBootTest from reloading application context between every test?

I've got this problem where my application context is reloaded between every test. I'm wiring in my actual application with functional test properties, wiremock etc. to create a functional test environment. Tests have always run fine but now we've added several it's become painfully slow due to the spring application being re-run everytime. The io.cucumber versions I'm using in my pom for cucumber-spring, cucumber-java, cucumber-junit is 7.11.1.
My Functional Test runner is annotated like this:
#RunWith(Cucumber.class)
#CucumberOptions(
features = "classpath:functional/features",
glue = {"com.iggroup.ds.functional.stepdefinitions"},
monochrome = true,
tags = "#FunctionalTest",
plugin = {"pretty", "html:target/cucumber-html-report", "junit:target/cucumber-xml-report.xml"}
)
public class FunctionalTestRunner {
#BeforeClass
public static void beforeClass() {
prepareEnvironment();
}
private static void prepareEnvironment() {
int applicationPort = SocketUtils.findAvailableTcpPort();
System.setProperty("server.port", String.valueOf(applicationPort));
System.setProperty("spring.active.profiles", "FUNCTIONAL_TEST");
System.setProperty("spring.cloud.config.enabled", "false");
System.setProperty("spring.cloud.config.server.bootstrap", "false");
}
}
Inside my glue package the Cucumber Configuration looks like this:
#AutoConfigureWireMock(port = 8089)
#CucumberContextConfiguration
#SpringBootTest(
classes = {
ServiceApplication.class,
RestClients.class
},
webEnvironment = DEFINED_PORT,
properties = {
"spring.profiles.active=FUNCTIONAL_TEST",
"spring.cloud.config.enabled = false"
}
)
public class FunctionalTestSpringCucumberConfiguration {
}
And lastly the application itself looks like this:
#EnableAsync
#EnableCaching
#EnableConfigServer
#SpringBootApplication
#EnableConfigurationProperties
public class ServiceApplication extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(ServiceApplication.class, args);
}
}
I had read somewhere before that the presence of #MockBean was causing unexpected refreshes between context although I never found out as to why - but I have none defined. As far as I can tell across the articles I've been reading, this shouldn't refresh my context every time so wondering if there's any way I can force it not to rewire the ServiceApplication.class in between every scenario?
#AutoConfigureWireMock(port = 8089)
By using Wiremock on fixed port you are dirtying the application context. This means a new application context will be created for each test. The code responsible for this prints a warning that you can see in your logs.
if (portIsFixed(testContext)) {
if (log.isWarnEnabled()) {
log.warn("You've used fixed ports for WireMock setup - "
+ "will mark context as dirty. Please use random ports, as much "
+ "as possible. Your tests will be faster and more reliable and this "
+ "warning will go away");
}
testContext.markApplicationContextDirty(DirtiesContext.HierarchyMode.EXHAUSTIVE);
}

How can I shutdown Spring boot thread pool project amicably which is 24x7 running

I have created spring boot thread pool project which has thread that needs to run 24x7 once spawned but when I need to stop the app in server for some maintenance it should shutdown after completing its current task and not taking up any new task.
My code for the same is:
Config class
#Configuration
public class ThreadConfig {
#Bean
public ThreadPoolTaskExecutor taskExecutor(){
ThreadPoolTaskExecutor executorPool = new ThreadPoolTaskExecutor();
executorPool.setCorePoolSize(10);
executorPool.setMaxPoolSize(20);
executorPool.setQueueCapacity(10);
executorPool.setWaitForTasksToCompleteOnShutdown(true);
executorPool.setAwaitTerminationSeconds(60);
executorPool.initialize();
return executorPool;
}
}
Runnable class
#Component
#Scope("prototype")
public class DataMigration implements Runnable {
String name;
private boolean run=true;
public DataMigration(String name) {
this.name = name;
}
#Override
public void run() {
while(run){
System.out.println(Thread.currentThread().getName()+" Start Thread = "+name);
processCommand();
System.out.println(Thread.currentThread().getName()+" End Thread = "+name);
if(Thread.currentThread().isInterrupted()){
System.out.println("Thread Is Interrupted");
break;
}
}
}
private void processCommand() {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void shutdown(){
this.run = false;
}
}
Main class:
#SpringBootApplication
public class DataMigrationPocApplication implements CommandLineRunner{
#Autowired
private ThreadPoolTaskExecutor taskExecutor;
public static void main(String[] args) {
SpringApplication.run(DataMigrationPocApplication.class, args);
}
#Override
public void run(String... arg0) throws Exception {
for(int i = 1; i<=20 ; i++){
taskExecutor.execute(new DataMigration("Task " + i));
}
for (;;) {
int count = taskExecutor.getActiveCount();
System.out.println("Active Threads : " + count);
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (count == 0) {
taskExecutor.shutdown();
break;
}
}
System.out.println("Finished all threads");
}
}
I need help to understand if I need to stop my spring boot application it should stop all the 20 threads running which runs (24x7) otherwise after completing there current loop in while loop and exit.
I would propose couple of changes in this code to resolve the problem
1) since in your POC processCommand calls Thread.sleep, when you shutdown the executor and it interrupts workers InterruptedException get called but is almost ignored in your code. After that there is if(Thread.currentThread().isInterrupted()) check which will return false for the reason above. Similar problem is outlined in the post below
how does thread.interrupt() sets the flag?
the following code change should fix the problem:
private void processCommand() {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
shutdown();
}
}
2) Also because of ThreadConfig::taskExecutor executorPool.setWaitForTasksToCompleteOnShutdown(true) Spring will call executor.shutdown instead of executor.shutdownNow. According to javadoc ExecutorService.shutdown
Initiates an orderly shutdown in which previously submitted tasks are
executed, but no new tasks will be accepted.
So I would recommend to set
executorPool.setWaitForTasksToCompleteOnShutdown(false);
Other things to improve in this code: although DataMigration is annotated as a component the instances of this class are creared not by Spring. You should try using factory method similar to ThreadConfig::taskExecutor in order to make Spring initiate instances of DataMigration for example to inject other bean into DataMigration instances.
In order to shutdown executor when running jar file on linux environment you can for example add actuator module and enable shutdown endpoint:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
in application.properties:
endpoints.shutdown.enabled=true
It will enable JMX shutdown endpoint and you can call shutdown on it.
If you want current job cycle of the task to be finished you should set
executorPool.setWaitForTasksToCompleteOnShutdown(true);
In order to connect to your jvm process on linux env remotely you have to specify an RMI Registry port.
Here is a detailed article:
How to access Spring-boot JMX remotely
If you just need to connect to JMX from local env you can run jsoncole or command-line tools : Calling JMX MBean method from a shell script
Here is an example uf using one of these tools - jmxterm
$>run -d org.springframework.boot: -b org.springframework.boot:name=shutdownEndpoint,type=Endpoint shutdown
#calling operation shutdown of mbean org.springframework.boot:name=shutdownEndpoint,type=Endpoint with params []
#operation returns:
{
message = Shutting down, bye...;
}

404 on Properly mapped SpringBoot RestController

I'm experiencing a little issue that is wasting a lot of my time...
I've created, for demonstration purposes, a simple SpringBoot application using the Eclipse New > Spring Starter Project.
Here is my Application class:
package it.asirchia;
//All needed imports
#SpringBootApplication
public class Application {
public static HashMap<Long,Book> books = new HashMap<Long, Book>();
public static HashMap<Long,Editor> editors = new HashMap<Long, Editor>();
public static HashMap<Long,Person> authors = new HashMap<Long, Person>();
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
Then I've created the EditorsApis Controller:
package it.asirchia.apis;
//All needed imports
#RestController
#RequestMapping(value="/editors")
public class EditorsApis {
private static long counter = 0;
#RequestMapping(value="/", method=RequestMethod.GET)
public HashMap<Long, Editor> getAllEditor(){
return Application.editors;
}
#RequestMapping(value="/", method=RequestMethod.POST)
public void postNewEditor(#RequestBody Editor editor){
Application.editors.put(counter++, editor);
}
#RequestMapping(value="/{editorid}", method=RequestMethod.PUT)
public void updateEditor(#PathVariable long editorid,
#RequestBody Editor editor){
Application.editors.put(editorid, editor);
}
#RequestMapping(value="/{editorid}", method=RequestMethod.GET)
public Editor getEditor(#PathVariable long editorid){
return Application.editors.get(editorid);
}
#RequestMapping(value="/{editorid}", method=RequestMethod.DELETE)
public void deleteEditor(#PathVariable long editorid){
Application.editors.remove(editorid);
}
}
And an AuthorsApis and a BooksApis controllers that are very similar to the EditorApis one.
Of course I've created too all the three Pojos:
Editor.class, Person.class and Book.class
I've started up the Eclipse embedded Spring runtime and I can see that all the paths are properly mapped:
INFO [main] s.w.s.m.m.a.RequestMappingHandlerMapping Mapped "
{[/authors/],methods=[GET]}" onto public java.util.HashMap it.asirchia.apis.AuthorsApis.getAllAuthors()
And so on and so forth for all the other Rest APIs I've implemented.
The last three lines of the log are:
Starting beans in phase 0
Tomcat started on port(s): 8080 (http)
Started Application in 5.547 seconds (JVM running for 6.169)
Ok, for me wverything is properly configured, up and running. But when I try to invoke
GET /authors HTTP/1.1
Host: localhost:8080
I obtain:
{
"timestamp": 1507286437765,
"status": 404,
"error": "Not Found",
"message": "No message available",
"path": "/authors"
}
And the same happens for ALL the REST APIs I've implemented.
Any idea about the reason of this problem?
Thank you.
The following mapping will work localhost:8080/authors/ for you.Since in your method mapping GET you have added the "/" so you should provide the trailing slash in URL also. If you want mapping like this localhost:8080/authors then follow the below code,
#RequestMapping(value={"","/"}, method=RequestMethod.GET)
public HashMap<Long, Editor> getAllEditor(){
return Application.editors;
}
The above will accept,
1) localhost:8080/editors
2) localhost:8080/editors/
Hope this will help.
Can you just try to add a action content in value.Here only specifying only a "/".Like
#RequestMapping(value="/updateEditor", method=RequestMethod.GET)
If you need to add any path variable,you can modify the same with following,
#RequestMapping(value="/updateEditor/{editorid}", method=RequestMethod.PUT)
Just try this method also.

spring scheduling a job with fixed delay and initial delay

I am trying o schedule a method call. I want to schedule this method call as soon as server starts and then after every 30 seconds.
Below code:
#Configuration
#EnableScheduling
#EnableTransactionManagement
public class Schedular implements SchedulingConfigurer {
#Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
taskRegistrar.setScheduler(poolScheduler());
taskRegistrar.addTriggerTask(new Runnable() {
#Override
public void run() {
testScheduling();
}
}, new Trigger() {
#Override
public Date nextExecutionTime(TriggerContext triggerContext) {
Calendar nextExecutionTime = Calendar.getInstance();
nextExecutionTime.add(Calendar.SECOND, <some value from database>);
return nextExecutionTime.getTime();
}
});
}
#Bean
public TaskScheduler poolScheduler() {
ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
scheduler.setThreadNamePrefix("poolScheduler");
scheduler.setPoolSize(10);
return scheduler;
}
public void testScheduling(){
System.out.println("Scheduling Testing");
}
}
The code below schedule the method code after 30 seconds after the server started BUT NOT just after server started. I know I need to do some other config to schedule the method call just after server start and then after every 30 seconds (or whatever time I want to).
I am using spring boot. Could anyone please suggest.
Also, is it possible to get both initial and fixeddelay/fixedrate value from database. I want to set the initial value as well from database
Thanks in advance.
let me know if this worked for you
#PostConstruct
#Scheduled(fixedDelay=30000)
public void testScheduling(){
System.out.println("Scheduling Testing");
}
Use the #PostConstuct annotation to start the method after the application starts.
You can use like below. I had used Spring Boot version v2.2.7
#Scheduled(fixedRateString = "${echo.interval(milliseconds)}", initialDelayString = "${echo.initialDelay(milliseconds)}")
The properties should be mentioned in "application.properties" file for the Spring Boot to detect and inject the values of the fixed rate and initial delay into the Scheduler.

Report metrics during shutdown of spring-boot app

I have a shutdownhook which is successfully executed, but the metrics is not reported. Any advice is appreciated! I guess the issues can be
StatsDMetricWriter might be disposed before the shutdown hook? How can I verify? Or is there a way to ensure the ordering of the configured singletons?
The time gap between metric generation and app shutdown < configured delay. I tried spawning a new Thread with Thread.sleep(20000). But it didn't work
The code snippets are as follows:
public class ShutDownHook implements DisposableBean {
#Autowired
private MetricRegistry registry;
#Override
public void destroy() throws Exception {
registry.counter("appName.deployments.count").dec();
//Spawned new thread here with high sleep with no effect
}
}
My Metrics Configuration for dropwizard is as below:
#Bean
#ExportMetricReader
public MetricRegistryMetricReader metricsDWMetricReader() {
return new MetricRegistryMetricReader(metricRegistry);
}
#Bean
#ExportMetricWriter
public MetricWriter metricWriter() {
return new StatsdMetricWriter(app, host, port);
}
The reporting time delay is set as 1 sec:
spring.metrics.export.delay-millis=1000
EDIT:
The problem is as below:
DEBUG 10452 --- [pool-2-thread-1] o.s.b.a.m.statsd.StatsdMetricWriter : Failed to write metric. Exception: class java.util.concurrent.RejectedExecutionException, message: Task com.timgroup.statsd.NonBlockingUdpSender$2#1dd8867d rejected from java.util.concurrent.ThreadPoolExecutor -- looks like ThreadPoolExecutor is shutdown before the beans are shutdown.
Any Suggestions please?
EDIT
com.netflix.hystrix.contrib.metrics.eventstream.HystrixMetricsPoller.getCommandJson() has the following piece of code
json.writeNumberField("reportingHosts", 1); // this will get summed across all instances in a cluster
I'm not sure how/why the numbers will add up? Where can I find that logic?

Resources