I have a Spring MVC project and Im currently trying to invoke a scheduler task from my restController. I have created a StartupBean and which contains a start() that actually invokes the TimerTask. Sample code below
public void start() throws Exception {
LOGGER.info("Entering start method {}", System.currentTimeMillis());
try {
// running timer task as daemon thread
TimerTask counterTimerTask = new SessionCountTask();
Timer counterTimer = new Timer(true);
counterTimer.scheduleAtFixedRate(counterTimerTask, 0, (long) 10 * 1000);//10 sec
} catch (Exception e) {
LOGGER.error("Error in start method of startup Bean {}", e);
} finally {
LOGGER.info("Exiting start method {}", System.currentTimeMillis());
}
}
From the Rest controller, Im just invoking the above start() method of the StartupBean. The above method doesnot return anything. The SessionCountTask class contains a method which returns a JSON object. I wanted to know how I can get the json response to the controller. The scheduler is scheduled to run every 10 secs and I would like to know how to get the response from the task every 10sec and display in the controller.
Any help on this is much appreciated.
Thanks in Advance.
Related
Could somebody help me to do the following:
#PostContruct public void func() {
webclient.get()...subscribe();
}
webclient call will terminate after func() returns. Most likely it will happen before the first request comes in, but no guarantees. The other option is to block(), which defeats the purpose of being reactive.
What would be the right way to make reactive calls in #PostConstruct methods?
Thank you.
I created a simple bean.
Synchronous update:
#Component
public class BeanTest {
private String postConstructValue;
#PostConstruct
public void init(){
try {
Thread.sleep(5000);
this.postConstructValue = "Construction done";
} catch (InterruptedException e) {
e.printStackTrace();
}
}
#Scheduled(fixedRate = 500)
public void print(){
System.out.println(
this.postConstructValue
);
}
}
It took some time for app to start (more than 5 seconds) because we simulated some time consuming process in the post construct. Scheduled print method started printing only after the app started. It started printing "Construction done" message.
Asynchronous update:
#Component
public class BeanTest {
private String postConstructValue;
#PostConstruct
public void init(){
Flux.just("Construction done")
.delayElements(Duration.ofSeconds(5))
.subscribe(s -> this.postConstructValue = s);
}
#Scheduled(fixedRate = 500)
public void print(){
System.out.println(
this.postConstructValue
);
}
}
Now in this approach, the app started within 2 seconds. Print method starting printing null for few seconds. Then it started printing "Construction done". It does not terminate the Flux postConstruct value update. It happened asynchronously.
Reactive approach is good when you want a non-blocking behavior and getting something done asynchronously. If you think that your component creation should wait for proper construction, you have to block! Otherwise, you can go with second approach.
We are trying to create a central batch service which will invoke batch processes in remote (micro) services. During this, we want to pause step execution untill remote service is not responding back to batch service.
Is this achievable with Spring Batch?
You can try implementing StepListener, where you have beforeStep and afterStep methods, you can control in beforeStep method call to wait until the other service call completes its execution
public class StepTwoListener implements StepExecutionListener {
#Override
public void beforeStep(StepExecution stepExecution) {
long start = System.currentTimeMillis();
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Sleep time in ms = "+(System.currentTimeMillis()-start));
System.out.println("Before Step Execution");
}}
and you can use the listener inside your step
#Bean
public Step stepTwo() {
return stepBuilderFactory.get("stepTwo").tasklet(new StepTwo()).listener(new StepTwoListener()).build();
}
In my Spring application, there is a scheduler for executing some task. Scheduled annotation is not used there because the schedule is quite complicated - it is dynamic and it used some data from the database. So simple endless cycle with thread sleeping is used. And sleeping interval is changed according to some rules. Maybe all this can be done with Scheduled annotation, but the question is not about that.
Below is simple example:
#Service
public class SomeService {
#PostConstruct
void init() {
new Thread(() -> {
while (true) {
System.out.println(new Date());
try {
Thread.sleep(1000);
} catch (Exception ex) {
System.out.println("end");
return;
}
}
}).start();
}
}
The code works fine but there is some trouble with killing that new thread. When I stop the application from Tomcat this new thread is continuing to run. So on Tomcat manage page I see that application is stopped, but in Tomcat log files I still see the output from the thread.
So what the problem? How I should change the code so the thread would be killed when the application is stopped?
Have you tried to implement a #PreDestroy method which will be invoked before WebApplicationContext is closed to change a boolean flag used in your loop? Though it seems strange that your objects are not discarded even when application is stopped...
class Scheduler {
private AtomicBoolean booleanFlag = new AtomicBoolean(true);
#PostConstruct
private void init() {
new Thread(() -> {
while (booleanFlag.get()) {
// do whatever you want
}
}).start();
}
#PreDestroy
private void destroy() {
booleanFlag.set(false);
}
}
i have a spring boot aplication and i want send email with javamail using ses on aws. but if I send an email, while it and sent no other process is executed.
I want to send the email through a thread, but I've implemented a thread in this way and even then the email sending process is not asynchronous.
when I make this request to send email and then list all to see how the processing is, as long as the sending of the email does not finish the list request is not executed
#GetMapping
public ResponseEntity<?> listarUsuarios(){
System.out.println("--------begin send mail------------");
new SendMail(emailService).run();
System.out.println("--------finish send mail------------");
List<Usuario> usuariosList = usuarioRepository.findAll(); // <- this process not is processed when send email not finish
return new ResponseEntity<>(usuariosList,HttpStatus.OK);
}
.
public class SendMail extends Thread {
public EmailService emailService;
public SendMail(EmailService emailService) {
this.emailService = emailService;
}
public void run(){
try {
emailService.EnviarEmailDeConfirmacao("daviresio#gmail.com", 1, "Subject test mail","body test mail");
} catch (Exception e) {
e.printStackTrace();
}
}
}
You are not starting a new thread. Instead, you are calling the run() method directly:
new SendMail(emailService).run();
Call start() instead to start a new thread:
new SendMail(emailService).start();
By the way, starting new threads like this from a web application is bad practice. It's better to use for example an ExecutorService to manage the threads that send e-mails, so that you don't get a potentially unlimited number of threads when many users are calling this functionality at the same time.
You should use the start() method to spawn as a new thread. If you call run() directly it is run in the same thread. See https://docs.oracle.com/javase/tutorial/essential/concurrency/runthread.html
Use start() instead of run().
Run will execute it on the existing thread.
Start will execute it on a new thread.
So change your code to the following if you want it to execute asynchronous:
new SendMail(emailService).start();
new SendMail(emailService).start(); - will start a new Thread and will execute SendMail.run(); in the new Thread.
new SendMail(emailService).run(); - is just a method call which executed in the same thread.
I used EJB Timer task to perform my periodic service query to database and send the update to client within specific period. This period is defined by client.
I pass the client request to the ejb timer stateless session bean. The request is stored as a instance variable.
When I call timer task through JNDI I set the client request to this instance variable and its available before timerService.createTimer() call. But when the #Timeout happen the instance variable is null.
I need this client request to perform DB query to find request parameters.
#Stateless
public class PeriodicService implements TimerRemote{
#Override
public void initializeTimer(Date firstDate, long timeout, String info) throws RemoteException {
try {
// below line show the request is not null.
System.out.println("request in initializeTimer "+this.request);
// create onetime service now.
timerService.createTimer(firstDate, info);
log.info("Timer created at " + firstDate + " with info: " + info);
} catch (Exception e) {
log.fatal("Exception after create timer : "+ e.toString());
e.printStackTrace();
}
}
#Timeout
public void ejbTimeout(Timer arg0) {
// below line show the requst as null
log.debug("Request in ejbTimeout "+this.request);
}
public void setRequest(IVEFRequest request) {
this.request = request;
}
private IVEFRequest request = null;
}
I'm new to EJB. Some thing wrong the way I do it? or how can I keep the request variable available until I cancel/stop the timer
You can try below code, no need to create a separate instance variable.
Provide the object that you would like to receive in timeout method while creating timer.
timerService.createTimer(firstDate, request);
Then, fetch the object in timeout method which was passed at timer creation.
(IVEFRequest)arg0.getInfo();