Trigger #Scheduled method - java

I use Spring's scheduler (#EnableScheduling) and have the following #Scheduled method, which is called every minute:
#Component
public class ScheduledTask {
#Scheduled(fixedRate = 60*1000)
public void run() {
// ...
Now I would like to be able to trigger a scheduler run, on demand, from another place in the code.
I can inject ScheduledTask and just call the run method. However I want to make sure that there is only one thread running the run method at any given time. In other words, if the scheduler is currently running run I want the call to be ignored.
Also I want to call run asynchronously, but this can be easily addressed by using #EnableAsync and #Async.
Is there any Spring feature that can be used in this scenario?

Edited as of comment:
Just use an AtomicBoolean.
#Component
public class ScheduledTask {
private AtomicBoolean isRunning = new AtomicBoolean(false);
#Scheduled(fixedRate = 60*1000)
public void run() {
if (isRunning.compareAndSet(false, true)) {
// ... do your things
//whenever you are done
isRunning.set(false);
}
I don't think there's something simpler in Spring. It makes no sense as it is really a flag thing.
Edit:
If you want to use it in several places of the application, consider implementing your own annotation with the semaphore or atomic boolean embedded.

Related

Execute a method after the application starts using Spring

I have this structure in my Service component in my Spring:
#Autowired
PointController controller;
#Autowired
ParametroService parametroService;
Timer timer = new Timer();
TimerTask timerTask = new TimerTask() {
#Override
public void run() {
List<IntRaptMec> allPointments = getNotValidated();
for(IntRaptMec pointment : allPointments) {
controller.validate(pointment.getIdTemp());
}
}
};
public void doValidationsTask() {
Parametro parametroTempo = parametroService.getParametro("1", "ATRC_MEC", "TEMPO_VERIFICACAO");
timer.scheduleAtFixedRate(
timerTask,
Integer.parseInt(parametroTempo.getValor()) * oneMinute,
Integer.parseInt(parametroTempo.getValor()) * oneMinute
);
}
All that I want is that after the Spring Application fully initializes it will execute the method run() inside the TimerTask. Then, after a given time in minutes that will be get from the parametroService.getParametro(), execute this task again.
I tried to follow this link from the docs:
https://docs.spring.io/spring/docs/current/spring-framework-reference/integration.html#scheduling-annotation-support
But seems that I can't dinamically sets the Delay time that a specific task will be executed
You can annotate your run() method with #EventListener or create a new such annotated method which will call run():
#EventListener
public void handleContextRefresh(ContextRefreshedEvent event) {
run();
}
If you don't use context which supports refresh() operation, you should be fine.
If you use such context (and you don't want run() to execute on context refresh) make sure you store this state within your bean.
More info on standard Spring events.
You are correct that annotation #Scheduled does not allow you to read delay parameter dynamically. For that reason and because this annotation takes delay parameter only in milliseconds or as crone expression which is not user friendly, I wrote my own utility that does it. The Utility is available as part of Open Source MgntUtils library. You will need to write your classes that will extend classes provided in the library and then you will get the desired functionality. But it does require a little bit of work. However the library comes with example package that has source code of working example with detailed explanation in javadoc. If you are interested library is available at Github and at Maven Central. In both places it is available with sources and javadoc. The desired feature is described in detail in javadoc. If you download and unzip javadoc into folder c:\tmp then look at URL file:///C:/tmp/javadoc/com/mgnt/lifecycle/management/backgroundrunner/package-summary.html for detailed description on how to use this feature. For working code example look in the sources at package com.mgnt.lifecycle.management.backgroundrunner.example
Also, there is an article that explains about the features of the library, except that this particular feature is not described in that article yet. Here is the link: Open Source Java library with stack trace filtering, Silent String parsing, Unicode converter and Version comparison
You can implement a spring SmartLifecycle interface. This will get invoked when Spring context is loaded completely. And Then you can start the timertask.
public class TimerTaskInvoker implements SmartLifecycle{
#override
public void start(){
timer.scheduleAtFixedRate(timerTask);
}
}
You can check the reference - https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/context/SmartLifecycle.html
#PostConstruct may be the annotation you need.
https://www.baeldung.com/running-setup-logic-on-startup-in-spring
You can use spring scheduler and specify the initialDelay and fixedRate using the #Scheduled annotation.
#EnableScheduling
class CustomScheduler{
#Scheduled(fixedRate = 1000, initialDelay = 1000)
public void taskYouWantToPerform() {
List<IntRaptMec> allPointments = getNotValidated();
for(IntRaptMec pointment : allPointments) {
controller.validate(pointment.getIdTemp());
}
}
}
For more details refer this

Observable.create is never called during tests when using the looper's scheduler

I have been working on this issue for some time now
This is the code I am testing
public Observable<Void> prepare() {
return Observable.<Void>create(subscriber -> {
// Some work is being done here but this part is never reached
subscriber.onCompleted();
}).subscribeOn(scheduler);
}
The scheduler is the looper's scheduler (the class inherits from HandlerThread)
The test I am writing is as follows:
#Test
public void prepare() throws Exception {
TestSubscriber<Void> testSubscriber = new TestSubscriber<>();
subject.start();
Observable<Void> obs = subject.prepare();
obs.subscribe(testSubscriber);
testSubscriber.awaitTerminalEvent(15, TimeUnit.SECONDS);
//assertions go here
subject.quit();
}
The problem is the code in the Observable.create is never reached and the testSubscriber's timeout is always hit.
I've checked that the looper runs and that the scheduler exists. It works well when I run the app. I am using RobolectricTestRunner.
Any ideas why the code is never reached?
Scheduler used in production code:
.subscribeOn(scheduler)
and scheduler used in test:
obs.subscribe(testSubscriber)
Are not the same. Please make your Presenter (or whatever holds prepare() method) to obtain scheduler. Than in production code pass your normal scheduler and in tests your TestSchubscriber.
OK, I found the answer.
This is how my test looks now:
#Test
public void prepare() throws Exception {
TestSubscriber<Void> testSubscriber = new TestSubscriber<>();
subject.start();
Observable<Void> obs = subject.prepare();
obs.subscribe(testSubscriber);
shadowOf(subject.getLooper()).getScheduler().advanceToNextPostedRunnable();
testSubscriber.awaitTerminalEvent(15, TimeUnit.SECONDS);
//assertion go here
subject.quit();
}
The problem I had is that Robolectric shadows the looper class and thus runnables that were queued there were never called.
In order to solve this I interacted with the shadow class and got it to run the Observable.create. I tried it before but I did it before I called subscribe and it must be called afterwards. This helped me understand that.
Now it works fine. Thanks to all who tried.

Spring-Boot with Swing UI

I want to use dependency injection for my Swing UI components in a Spring-Boot application and having a hard time figuring out, how to properly execute the UI behavior on the Event Dispatch Thread.
What I came up with first was like this:
App
#SpringBootApplication
public class App {
private static AppView view;
#Bean
public AppView appView() {
return view;
}
public static void main(String[] args) throws Exception {
SwingUtilities.invokeLater(() -> view = new AppView());
SpringApplication app = new SpringApplication(App.class);
app.run(args);
}
}
AppView
public class AppView extends JFrame {
...
#Inject
private DependencyWithTimeConsumingOperations backendController;
#Inject
private JPanel someChildComponent;
#PostConstruct
public void init() {
constructView(); // inits frame properties and child components
showView();
}
private void showView() {
SwingUtilities.invokeLater(() -> {
pack();
setVisible(true);
});
}
...
}
The backend dependency gets called when certain UI events occur. What I observe is, that the backend calls get excuted on the EDT instead of the main application thread, which is bad, I assume. As I understand, not having much experience with Swing, is, that only UI updates should be executed on the EDT.
Is there a better way to wire my dependencies so that everything is executed in its proper thread? What I could find out so far seems a bit outdated or I plainly did not understand the answers :-)
Not sure if it is still relevant to you after so long :), but since it may help others, I'll try to answer.
Spring is only injecting the objects, it is not managing the threads. The behaviour would be the same if you'd instantiated and set the backendController manually, meaning that the EDT (or any thread that is calling the operation) would be the one to execute the code on the controller.
If you explicitly want to run in a different thread, we'd need to know more about the methods in the controller. Are they methods that you want to call and not wait for a reply (fire and forget)? Or maybe you need the reply but can run more than one at the same time? In these scenarios you can take advantage of the Executors class and do something like:
Executors.newSingleThreadExecutor().execute(() -> backendController.timeConsumingOperation1()); // Fire and forget. The operation timeConsumingOperation1 will be executed by a separate thread and the EDT will continue to the next line (won't freeze your GUI)
If you need a result, you may submit it to the pool and poll for the result (maybe with a "refresh" button on the screen). Keep in mind that as soon as you call "get()" the current thread will wait for the pooled thread to finish before proceeding to the next line.
Future result = Executors.newSingleThreadExecutor().execute(() -> backendController.timeConsumingOperation2);
result.isDone(); // You can add a "refresh" button or a scheduled task to check the state...
doSomething(result.get()); // This will hold the current thread until there is a response from the thread running the timeConsumingOperation
Or maybe you do want to freeze the GUI until you have a response from all methods called in the controller, but they can be safely called in parallel:
ExecutorService executorService = Executors.newFixedThreadPool(2);
List<Future<Object>> results = executorService.invokeAll(
Arrays.asList(() -> backendController.timeConsumingOp3(), () -> backendController.timeConsumingOp4));
results.forEach(e -> doSomething(e.get())); // The tasks will be executed in parallel and "doSomething()" will be called as soon as the result for the given index is available
executorService.shutdown(); // Always shutdown
Of course this is just an example, but in large Swing applications it is good practice to create pools of threads (shared by the controllers) to which we submit our long running tasks. You can configure the pool size based on the number of cores (Runtime.getRuntime().availableProcessors()) to best use the resources available on the machine (the tasks submitted will be queued up with no restriction, but only X threads will execute the tasks in parallel, where X is the pool size).
Just use code
SpringApplicationBuilder(Main.class).headless(false).run(args);

Using guava AbstractScheduledService

I'm trying to execute some task periodically using guava AbstractScheduledService :
public class MyService extends AbstractScheduledService {
public MyService() {
}
#Override
protected void runOneIteration() {
doStuff();
}
private void doStuff() {
// Do stuff
}
#Override
protected Scheduler scheduler() {
return Scheduler.newFixedRateSchedule(0, 8, TimeUnit.HOURS);
}
}
So this service should execute some task periodically every 8 hours but it never actually does. The inherited isRunning() method returns false and the runOneIteration() method never gets invoked.
I have managed to make it work by calling the startAsync() method (inherited from parent class) from my service constructor but I don't see any reference saying this is the way it should work.
Have I missed something here? Is this the way the AbstractScheduledService works?
AbstractScheduledServiced implements Service. The Service interface describes lifecycle methods including startAsync. The ServiceState enum literals contain documentation on what they mean. A Service in NEW state (just created):
A service in this state is inactive. It does minimal work and consumes minimal resources.
For the Service to do something useful you have to transition it to the state RUNNING
A service in this state is operational.
That's why you have to start the Service before it does anything.
I would also advise against calling startAsync from the constructor and instead calling it from the Code that creates your MyService instance. It is rarely an expected thing to have such heavy side effects (creation of Threads) in the constructor.

How do I write a JUnit test case to test threads and events

I have a java code which works in one (main) thread. From the main thread, i spawn a new thread in which I make a server call. After the server call is done, I am doing some work in the new thread and after that the code joins the main thread.
I am using eclipse Jobs to do the server call.
I want to know, how do I write a JUnit test case for this.
You may need to restructure your code so that it can be easily tested.
I can see several distinct areas for testing:
Thread Management code: the code that launches the thread(s) and perhaps waits for results
The "worker" code run in the thread
The concurrency issues that may result when multiple threads are active
Structure your implementation so that Your Thread Management code is agnostic as to the details of the Worker. Then you can use Mock Workers to enable testing of Thread Management - for example a Mock Worker that fails in certain ways allows you to test certain paths in the management code.
Implement the Worker code so that it can be run in isolation. You can then unit test this independently, using mocks for the server.
For concurrency testing the links provided by Abhijeet Kashnia will help.
This is what I created ConcurrentUnit for. The general usage is:
Spawn some threads
Have the main thread wait or sleep
Perform assertions from within the worker threads (which via ConcurrentUnit, are reported back to the main thread)
Resume the main thread from one of the worker threads once all assertions are complete
See the ConcurrentUnit page for more info.
I'm guessing that you may have done your mocking code and may want a simple integration test to ensure that that your server call works.
One of the difficulties in testing threads comes from their very nature - they're concurrent. This means that you're force into writing JUnit test code that is forced to wait until your thread has finished its job before testing your code's results. This isn't a very good way of testing code, and can be unreliable, but usually means that you have some idea about whether you code is working.
As an example, your code may look something like:
#Test
public void myIntegrationTest() throws Exception {
// Setup your test
// call your threading code
Results result = myServerClient.doThreadedCode();
// Wait for your code to complete
sleep(5);
// Test the results
assertEquals("some value",result.getSomeValue());
}
private void sleep(int seconds) {
try {
TimeUnit.SECONDS.sleep(seconds);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
I really don't like doing this and prefer mocks and agree with the other answers. But, if you need to test your threads, then this is one approach that I find works.
When your only problem is waiting for the result, use ExecutorService for spawning your threads. It can accept work jobs both as Runnable and Callable. When you use the latter, then you are given a Future object in return, that can be used to wait for the result. You should consider using ExecutorService anyway, as from what I understand, you create many threads, and this is a perfect use case for executor services.
class AnyClass {
private ExecutorService threadPool = Executors.newFixedThreadPool(5);
public List<Future<Integer>> anyMethod() {
List<Future> futures = new ArrayList<>();
futures.add(threadPool.submit(() -> {
// Do your job here
return anyStatusCode;
}));
futures.add(threadPool.submit(() -> {
// Do your other job here
return anyStatusCode;
}));
return futures;
}
}
And the test class:
class TestAnyClass {
#Test
public void testAnyMethod() {
AnyClass anyObject = new AnyClass();
List<Future<Integer>> futures = anyObject.anyMethod();
CompletableFuture[] completable = futures.toArray(new CompletableFuture[futures.size()]);
// Wait for all
CompletableFuture.allOf(completable).join();
}
}
I suggest you use a mocking framework, to confirm that the server call was indeed made. As for the thread unit testing: Unit testing multithreaded applications
The resources provided by Abhijeet Kashnia may help, but I am not sure what you are trying to achieve.
You can do unit testing with mocks to verify your code, that won't test concurrency but will provide coverage.
You can write an integration test to verify that the threads are being created and joined in the fashion you expect.However this will not guarantee against concurrency problems. Most concurrent problems are caused by timing bugs which are not predictable and thus can't be tested for accurately.
Here is my solution to test asynchrone method which used thread.start:
public class MyClass {
public void doSomthingAsynchrone() {
new Thread(() -> {
doSomthing();
}).start();
}
private void doSomthing() {
}
}
#RunWith(PowerMockRunner.class)
#PrepareForTest(MyClass.class)
public class MyClassTest {
ArgumentCaptor<Runnable> runnables = ArgumentCaptor.forClass(Runnable.class);
#InjectMocks
private MyClass myClass;
#Test
public void shouldDoSomthingAsynchrone() throws Exception {
// create a mock for Thread.class
Thread mock = Mockito.mock(Thread.class);
// mock the 'new Thread', return the mock and capture the given runnable
whenNew(Thread.class).withParameterTypes(Runnable.class)
.withArguments(runnables.capture()).thenReturn(mock);
myClass.doSomthingAsynchrone();
runnables.getValue().run();
/**
* instead of 'runnables.getValue().run();' you can use a real thread.start
*
* MockRepository.remove(Thread.class);
* Thread thread = new Thread(runnables.getValue());
* thread.start();
* thread.join();
**/
verify(myClass, times(1)).doSomthing();
}
}

Categories