Spring Scheduler/Threading working doesnt work on centos minimal - java

I created a spring boot app which has a scheduler which runs every X seconds
Main Class :
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;
#SpringBootApplication
#EnableScheduling
public class FiobenchmarkApplication {
public static void main(String[] args) {
SpringApplication.run(FiobenchmarkApplication.class, args);
}
}
My Spring Scheduler class is as below
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
#Component
public class Scheduler {
#Scheduled(fixedRate=1000)
public void getFioResult(){
System.out.println("hello class");
}
}
After gradle clean build I get a jar named:fiobench.jar
The application runs perfectly and calls the scheduler every X seconds when I run on my local machine(Which is ubuntu)
When the jar is transfered to another machine (Centos 7 Minimal and both ubutnu and centos have same Java versions ) .
The scheduler is called only once at the start and is never called after it calls one time .
Has any one faced any such issue with spring scheduler.
Also When I try to replicate the same using normal java multi threading it doesnt work on centos minimal while it works on my ubuntu machine
Below is my pure java implementation of thread
public class Scheduler extends Thread implements Runnable{
//#Scheduled(fixedRate=1000)
public void getFioResult(){
}
#Override
public void run() {
// TODO Auto-generated method stub
while(true){
try {
getFioResult();
Thread.sleep(TimeUnit.SECONDS.toMillis(10));
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
And my main class is
public class FiobenchmarkApplication {
public static void main(String[] args) {
Scheduler s=new Scheduler();
s.start();
}
}

Related

Run two methods in a spring boot controller at the same time

I am spring boot beginner and I have a spring boot project which contain a controller and this controller contains two methods as shown bellow:
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
#RestController
public class Controller {
#GetMapping("/preliminate")
public void OpentextWebService(){
try {
OTService.threadOne();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
#GetMapping("/final")
public void OpentextWebService2(){
OTService.threadTwo();
}
}
the problem is that when I run : localhost:8080/preliminate and localhost:8080/final at the same time, only the first one will work. So is there is any way to run them at the same time?
I did some research and I found the #Async way but unfortunately I did not know how to impliment it in my code specially that I don't have a Service or Configuration Class.
The best way to implement this, is with #Async methods,
Create a Bean for you job Async.
#SpringBootApplication
#EnableAsync
public class ApplicationRun {
public static void main(String[] args) {
SpringApplication.run(ApplicationRun.class, args);
}
#Bean("threadPool")
public TaskExecutor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(20);
executor.setMaxPoolSize(1000);
executor.setWaitForTasksToCompleteOnShutdown(true);
executor.setThreadNamePrefix("Async-");
return executor;
}
}
And then, create a service bean with a method like

#Async("threadPool")
public void asyncTask1(){
OTService.threadOne();
}

#Async("threadPool")
public void asyncTask2(){
OTService.threadTwo();
}
And finally, call this service methods on your controller. Thats maybe works for you!

Ensuring spring boot and liquibase receive and handle SIGTERM

Currently running SpringBoot applications in a containerised environment (ECS) and I've observed scenarios in which the container gets terminated during start-up and while it's still holding the Liquibase changelock.
This leads to issues in all containers that are spun afterwards and ends up requiring manual intervention.
Is it possible to ensure that if the process receives a SIGTERM, it will gracefully handle termination and release the lock?
I've already ensured that the container is receiving the signals by enabling via InitProcessEnabled (in the CloudFormation template) and use of "exec java ..." as a java agent we use does gracefully shutdown on this circumstances.
Heyo,
As mentioned in the GitHub issue I have a workaround. A solution is yet to be implemented.
You can manually register a shutdown hook before running spring boot.. That hook should assure that the Termination is postponed until liquibase is done.
package dang;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
#EnableJpaRepositories
#SpringBootApplication
public class DangApplication {
public static void main(String[] args) throws InterruptedException {
Thread thread = new GracefulShutdownHook();
Runtime.getRuntime().addShutdownHook(thread);
new SpringApplicationBuilder(DangApplication.class)
.registerShutdownHook(true)
.logStartupInfo(true)
.build()
.run();
Runtime.getRuntime().removeShutdownHook(thread);
}
}
And the hook:
package dang;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import java.util.Map;
#Slf4j
public class GracefulShutdownHook extends Thread {
#SneakyThrows
#Override
public void run() {
super.run();
log.info("Shutdown Signal received.. Searching for Liquibase instances!");
boolean liquibaseIsRunning = true;
while (liquibaseIsRunning) {
Map<Thread,StackTraceElement[]> stackTraces = Thread.getAllStackTraces();
for(Map.Entry<Thread, StackTraceElement[]> entry : stackTraces.entrySet()) {
StackTraceElement[] stackTraceElements = entry.getValue();
for (StackTraceElement stackTraceElement : stackTraceElements) {
if (stackTraceElement.getClassName().contains("liquibase") && stackTraceElement.getMethodName().contains("update")) {
try {
log.warn("Liquibase is currently updating");
entry.getKey().join();
liquibaseIsRunning = false;
} catch (InterruptedException e) {
log.error("Shutdown Hook was interrupted.. Fatal databaselock may be imminent", e);
if (Thread.interrupted()) {
throw e;
}
}
}
}
}
}
}
}
EDIT
After implementing my workaround a contributor of liquibase shared a different solution (It's actually the same solution just through Spring functionality) which is much better than what I did:
package dang;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
#EnableJpaRepositories
#SpringBootApplication
public class DangApplication {
public static void main(String[] args) throws InterruptedException {
new SpringApplicationBuilder(DangApplication.class)
.initializers(ConfigurableApplicationContext::registerShutdownHook) // Registers application hook before liquibase executes.
.logStartupInfo(true)
.build()
.run();
}
}

How to make Java class run on startup using Context Listener without affecting other scheduled tasks?

I am using Eclipse in Apache Tomcat server to execute my java based web project.
I have to run a function written in the class, "socket.java" only once, when application starts. I tried to initialize this class, i have other scheduled tasks running on other thread implemented by other servletContextListner. When i run this 'Socket.Java' on ServletContextListner, then the application is not working properly. Now the scheduled tasks on other ServletContextListner is only running once.
How to solve this?
my Listener class is as below,:-
package com.my.classes;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
public class SocketContextListner implements ServletContextListener{
private Executor Task;
#Override
public void contextDestroyed(ServletContextEvent arg0) {
// TODO Auto-generated method stub
}
#Override
public void contextInitialized(ServletContextEvent arg0) {
// TODO Auto-generated method stub
Task= Executors.newSingleThreadExecutor();
Socket b = new Socket();
Task.execute(b);
}
}
The other ServletContextListener with many scheduled task, which is not running when i implemented the Context listener for Socket
package com.my.classes;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
public class JMonitorContextListner implements ServletContextListener{
private ScheduledExecutorService scheduler1;
#Override
public void contextDestroyed(ServletContextEvent event1) {
// TODO Auto-generated method stub
scheduler1.shutdownNow();
// System.out.println("Context1 Destroyed");
}
#Override
public void contextInitialized(ServletContextEvent event1) {
// TODO Auto-generated method stub
// System.out.println("Context1 initialized");
scheduler1 = Executors.newSingleThreadScheduledExecutor();
scheduler1.scheduleAtFixedRate(new Jmonitor(), 0, 10, TimeUnit.SECONDS);
scheduler1.scheduleAtFixedRate(new FeedStatus(), 0, 10, TimeUnit.SECONDS);
scheduler1.scheduleAtFixedRate(new AutoReset(), 0, 30, TimeUnit.SECONDS);
scheduler1.scheduleAtFixedRate(new AutoLogoff(), 0, 1, TimeUnit.MINUTES);
}
}
My web.xml file:
<listener>
<listener-class>com.my.classes.JMonitorContextListner</listener-class>
</listener>
<listener>
<listener-class>com.my.classes.SocketContextListner</listener-class>
</listener>
My Console:
console print such as The priority, ip from db and Null point exception are supposed to print again and again as it is from the scheduled task
Please suggest me, how to initialize the class "Socket.java" without affecting the normal working of application?
When i created separate listener for Socket.java and executed it on a different thread, my scheduled tasks on "JMonitorContextListner" stops after first run. Why is it happening?
Suggestion and any piece of code is highly appreciated.

Spring Boot shutdown hook

How can I register/add a custom shutdown routine that shall fire when my Spring Boot application shuts down?
Scenario: I deploy my Spring Boot application to a Jetty servlet container (i.e., no embedded Jetty). My application uses Logback for logging, and I want to change logging levels during runtime using Logback's MBean JMX configurator. Its documentation states that to avoid memory leaks, on shutdown a specific LoggerContext shutdown method has to be called.
What are good ways to listen on Spring Boot shutdown events?
I have tried:
public static void main(String[] args) throws Exception {
ConfigurableApplicationContext cac = SpringApplication.run(Example.class, args);
cac.addApplicationListener(new ApplicationListener<ContextClosedEvent>() {
#Override
public void onApplicationEvent(ContextClosedEvent event) {
logger.info("Do something");
}
});
}
but this registered listener does not get called when the application shuts down.
https://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/htmlsingle/#features.spring-application.application-exit
Each SpringApplication will register a shutdown hook with the JVM to ensure that the ApplicationContext is closed gracefully on exit. All the standard Spring lifecycle callbacks (such as the DisposableBean interface, or the #PreDestroy annotation) can be used.
In addition, beans may implement the org.springframework.boot.ExitCodeGenerator interface if they wish to return a specific exit code when the application ends.
have you tried this as mentioned by #cfrick ?
#SpringBootApplication
#Slf4j
public class SpringBootShutdownHookApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootShutdownHookApplication.class, args);
}
#PreDestroy
public void onExit() {
log.info("###STOPing###");
try {
Thread.sleep(5 * 1000);
} catch (InterruptedException e) {
log.error("", e);;
}
log.info("###STOP FROM THE LIFECYCLE###");
}
}
Your listener is registered too late (that line will never be reached until the context has already closed). It should suffice to make it a #Bean.
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletListenerRegistrationBean;
import org.springframework.boot.web.support.SpringBootServletInitializer;
import org.springframework.context.annotation.Bean;
#SpringBootApplication
#EnableAutoConfiguration
public class Application extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
#NotNull
#Bean
ServletListenerRegistrationBean<ServletContextListener> myServletListener() {
ServletListenerRegistrationBean<ServletContextListener> srb =
new ServletListenerRegistrationBean<>();
srb.setListener(new ExampleServletContextListener());
return srb;
}
}
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
public class ExampleServletContextListener implements ServletContextListener {
#Override
public void contextInitialized(
ServletContextEvent sce) {
// Context Initialised
}
#Override
public void contextDestroyed(
ServletContextEvent sce) {
// Here - what you want to do that context shutdown
}
}
I have a similar use case, where I have to hold the server's shutdown process for some minutes, I have used the same approach mentioned in the question, the only change is instead of adding the listener after booting the service, I have added the listener (ContextClosedEvent) before running the application
#SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication application = new SpringApplication(Application.class);
application.addListeners((ApplicationListener<ContextClosedEvent>) event -> {
log.info("Shutdown process initiated...");
try {
Thread.sleep(TimeUnit.MINUTES.toMillis(5));
} catch (InterruptedException e) {
log.error("Exception is thrown during the ContextClosedEvent", e);
}
log.info("Graceful Shutdown is processed successfully");
});
application.run(args);
}
}

How to execute a class file (include Main()) in my package folder on Jboss system as standalone

I hava a java project deployed in Jboss. When jboss started completely, I have to execute a class file that has a main() method automatically when jboss starts. that means TESTManager should be as like a standalone daemon. I have no idea how to execute it automatically in my project...
The class is provided below:
public class TESTMain {
public static void main(String[] args) {
try {
TESTManager testManager = new TESTManager();
testManager.start();
} catch (Exception e) {
e.printStackTrace();
}
}
}

Categories