How to send periodic messages using WebSocket? - java

I am using WebSocket on Tomcat (the actual implementation is Tyrus, the reference implementation of JSR 356). It works great, when I have to handle client messages, and respond to them. However, I would like implement a push solution for several of my client-side controls. Actually I need two type of solution:
pushing out data with a specific interval,
pushing out system messages, when they are raised.
For the first one, I think ScheduledExecutorService can be a solution, I already have a more or less working example, I have issues with cleaning up though. For the second one, I think I would need to have a thread, which would trigger a method in the WebSocket endpoint, but I don't really know how to do this cleanly either. And by clean, I mean that I would like to have running threads only if there are connected sessions to my endpoint.
To summarize my question: how would you properly implement a push message solution using the Java EE WebSocket API?
ps.: I would prefer a "pure" solution, but Spring is also not unwelcome.
Current code skeleton
This is how my current solution looks like for the first problem:
#ServerEndpoint(...)
public class MyEndPoint {
// own class, abstracting away session handling
private static SessionHandler sessionHandler = new SessionHandler();
private static ScheduledExecutorService timer =
Executors.newSingleThreadScheduledExecutor();
private static boolean timerStarted = false;
#OnOpen
public void onOpen(Session session, EndpointConfig config) {
sessionHandler.addSession(session);
if (!timerStarted) {
timer.scheduleAtFixedRate(new Runnable() {
#Override
public void run() {
sessionHandler.sendToAllSession("foo");
}
}, 0, 3, TimeUnit.SECONDS);
timerStarted = true;
}
}
#OnClose
public void onClose(Session session) {
sessionHandler.removeSession(session);
if (0 == sessionHandler.countSessions()) {
// TODO: cleanup thread properly
timer.shutdown();
try {
while (!timer.awaitTermination(10, TimeUnit.SECONDS));
} catch (InterruptedException e) {
log.debug("Timer terminated.");
}
timerStarted = false;
}
}
}
This works more or less, but after a few page reload, it dies with RejectedExecutionException and I am not so sure how to handle the situation.

Unfortunately you can't use any ExecutorService after shutdown();
So after OnClose() method next OnOpen() method will crash.
Just little code for demonstrate:
public class TestThread {
public static void main(String[] args) {
final ScheduledExecutorService timer = Executors.newSingleThreadScheduledExecutor();
boolean timerStarted = false;
//OnOpen - 1; - OK
if (!timerStarted) {
timer.scheduleAtFixedRate(new Runnable() {
#Override
public void run() {
System.out.println("foo");
}
}, 0, 3, TimeUnit.SECONDS);
timerStarted = true;
}
//OnOpen - 2; - OK
if (!timerStarted) {
timer.scheduleAtFixedRate(new Runnable() {
#Override
public void run() {
System.out.println("foo");
}
}, 0, 3, TimeUnit.SECONDS);
timerStarted = true;
}
//OnClose - 1 - OK
timer.shutdown();
timerStarted = false;
//OnOpen - 2; - NOT OK, because after stop you can't use timer, RejectedExecutionException will thrown
if (!timerStarted) {
// will crash at this invocke
timer.scheduleAtFixedRate(new Runnable() {
#Override
public void run() {
System.out.println("foo");
}
}, 0, 3, TimeUnit.SECONDS);
timerStarted = true;
}
}
}
You may try to use your class also as a web listener http://docs.oracle.com/javaee/7/api/javax/servlet/annotation/WebListener.html
and create timer in methods that executed on startup and destroy of server
#WebListener
#ServerEndpoint(...)
public class MyEndPoint implements ServletContextListener{
final ScheduledExecutorService timer = Executors.newSingleThreadScheduledExecutor();
#Override
public void contextInitialized(ServletContextEvent servletContextEvent) {
timer.scheduleWithFixedDelay(...)
}
#Override
public void contextDestroyed(ServletContextEvent servletContextEvent) {
timer.shutdown();
}
...
}

Related

Scheduler works incorrect in unit testing

I need to collect data from a public API. I want to collect it daily or twice a day.
public class AlphavantageStockRequestDispatcher {
public static void startAlphavantageStockScraper(int timeInterval) {
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
Runnable getStockList =
new Runnable() {
#Override
public void run() {
List<AlphavantageStock> stocks = AlphavantageStockRequest.getStockPrices(); //Method contains requests
StockDao<AlphavantageStock> dao = new JpaAlphavantageStockDao();
for (AlphavantageStock stock : stocks) {
dao.save(stock);
}
}
};
scheduler.scheduleAtFixedRate(getStockList, 0, timeInterval, TimeUnit.HOURS);
}
}
The problem is when I start it from the same class (just added main method and invoked startAlphavantageStockScraper(1); it works fine. But when I want to test it via JUnit it's not working (test class is in symmetric package name but test subfolder):
public class AlphavantageStockRequestDispatcherTest {
#Test
public void startDispatcher_TwoFullCycles_WithOneHourIntervalBetween() {
AlphavantageStockRequestDispatcher.startAlphavantageStockScraper(1);
}
}
While debugging I found out that in unit test execution a program reaches public void run() line then skips it. So there's no error. Program ends up correctly but does nothing useful.
Any help will be appreciated.
This is how asynchronous programming works. In the AlphavantageStockRequestDispatcher class you've just submitted a task but you have to wait for it's completed. There are several ways to handle this situation. I prefer state notification using java.util.concurrent.CountDownLatch. So some refactoring is recommended in AlphavantageStockRequestDispatcher class like this:
public class AlphavantageStockRequestDispatcher {
public static void startAlphavantageStockScraper(int timeInterval, CountDownLatch latch) {
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
Runnable getStockList =
new Runnable() {
#Override
public void run() {
System.out.println("worker started");
try {
Thread.sleep(10_000L);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
System.out.println("worker finished");
Optional.ofNullable(latch).ifPresent(CountDownLatch::countDown);
}
}
};
scheduler.scheduleAtFixedRate(getStockList, 0, timeInterval, TimeUnit.HOURS);
}
}
Now it's possible to test that.
public class AlphavantageStockRequestDispatcherTest {
#Test
void startDispatcher_TwoFullCycles_WithOneHourIntervalBetween() throws InterruptedException {
CountDownLatch latch = new CountDownLatch(1);
AlphavantageStockRequestDispatcher.startAlphavantageStockScraper(1, latch);
latch.await(20, TimeUnit.SECONDS);
System.out.println("first finished - need some assertions");
}
}

How to make JUnit4 "Wait" for asynchronous job to finish before running tests

I am trying to write a test for my android app that communicates with a cloud service.
Theoretically the flow for the test is supposed to be this:
Send request to the server in a worker thread
Wait for the response from the server
Check the response returned by the server
I am trying to use Espresso's IdlingResource class to accomplish that but it is not working as expected. Here's what I have so far
My Test:
#RunWith(AndroidJUnit4.class)
public class CloudManagerTest {
FirebaseOperationIdlingResource mIdlingResource;
#Before
public void setup() {
mIdlingResource = new FirebaseOperationIdlingResource();
Espresso.registerIdlingResources(mIdlingResource);
}
#Test
public void testAsyncOperation() {
Cloud.CLOUD_MANAGER.getDatabase().getCategories(new OperationResult<List<Category>>() {
#Override
public void onResult(boolean success, List<Category> result) {
mIdlingResource.onOperationEnded();
assertTrue(success);
assertNotNull(result);
}
});
mIdlingResource.onOperationStarted();
}
}
The FirebaseOperationIdlingResource
public class FirebaseOperationIdlingResource implements IdlingResource {
private boolean idleNow = true;
private ResourceCallback callback;
#Override
public String getName() {
return String.valueOf(System.currentTimeMillis());
}
public void onOperationStarted() {
idleNow = false;
}
public void onOperationEnded() {
idleNow = true;
if (callback != null) {
callback.onTransitionToIdle();
}
}
#Override
public boolean isIdleNow() {
synchronized (this) {
return idleNow;
}
}
#Override
public void registerIdleTransitionCallback(ResourceCallback callback) {
this.callback = callback;
}}
When used with Espresso's view matchers the test is executed properly, the activity waits and then check the result.
However plain JUNIT4 assert methods are ignored and JUnit is not waiting for my cloud operation to complete.
Is is possible that IdlingResource only work with Espresso methods ? Or am I doing something wrong ?
I use Awaitility for something like that.
It has a very good guide, here is the basic idea:
Wherever you need to wait:
await().until(newUserIsAdded());
elsewhere:
private Callable<Boolean> newUserIsAdded() {
return new Callable<Boolean>() {
public Boolean call() throws Exception {
return userRepository.size() == 1; // The condition that must be fulfilled
}
};
}
I think this example is pretty similar to what you're doing, so save the result of your asynchronous operation to a field, and check it in the call() method.
Junit will not wait for async tasks to complete. You can use CountDownLatch to block the thread, until you receive response from server or timeout.
Countdown latch is a simple yet elegant solution and does NOT need an external library. It also helps you focus on the actual logic to be tested rather than over-engineering the async wait or waiting for a response
void testBackgroundJob() {
Latch latch = new CountDownLatch(1);
//Do your async job
Service.doSomething(new Callback() {
#Override
public void onResponse(){
ACTUAL_RESULT = SUCCESS;
latch.countDown(); // notify the count down latch
// assertEquals(..
}
});
//Wait for api response async
try {
latch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
assertEquals(expectedResult, ACTUAL_RESULT);
}

Cancel asynchronous calls

We need to implement a feature that allows us to cancel a future job. Given that this job is doing DB calls and we need to rollback\cleanup any updates made before cancel was fired.
This is what I have tried, but "Thread.currentThread().isInterrupted()" always return false:
ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
final Future future = executor.submit(new Callable() {
#Override
public Boolean call() throws Exception {
// Do Some DB calls
if (Thread.currentThread().isInterrupted()) {
// Will need to roll back
throw new InterruptedException();
}
return true;
}
});
executor.schedule(new Runnable() {
public void run() {
future.cancel(true);
}
}, 1, TimeUnit.SECONDS);
Is this the right approach to achieve our target? And how to know if the job was cancelled in order to cancel\roll back changes?
I believe that you complete the database calls before the second task gets a chance to run. When you have only a single executor it is possible that it does not schedule time for the second scheduled task before the first completes. This following snippet does get interrupted:
import java.util.*;
import java.util.concurrent.*;
public class Main {
public static void main(String[] arg) {
ScheduledExecutorService runner = Executors.newScheduledThreadPool(2);
// If this is 1 then this will never be interrupted.
final Future f = runner.submit(new Callable<Boolean>() {
public Boolean call() throws Exception {
System.out.println("Calling");
while (! Thread.currentThread().isInterrupted()) {
;
}
System.out.println("Interrupted");
return true;
}
});
runner.schedule(new Runnable() {
public void run() {
System.out.println("Interrupting");
f.cancel(true);
}
}, 1, TimeUnit.SECONDS);
}
}
First it seems the thread pool is not creating new thread for you so your cancel task will get called only after the DB task finishes. So I changed the pool size in yours example to 2 and it worked.

How to gracefully stop Guava AbstractScheduledService using a shutdown hook?

I am using an AbstractScheduledService with a scheduler. A simple pattern like:
class MyService extends AbstractScheduledService {
// KEEP THIS VAR IN MIND W.R.T the SHUTDOWN_HOOK BELOW
public static volatile boolean keepRunning = true;
protected void startUp() throws Exception {
// startup stuff
}
protected void runOneIteration() throws Exception {
// main logic stuff
}
protected void shutDown() throws Exception {
// shutdown stuff
}
protected Scheduler scheduler() {
return Scheduler.newFixedRateSchedule(0, 1, TimeUnit.SECONDS);
}
}
Now, I want to implement a typical shutdown hook like this: (the below snippet will be in main method)
final Thread mainThread = Thread.currentThread();
LOGGER.debug("Adding the shutdown hook");
Runtime.getRuntime().addShutdownHook(new Thread() {
#Override
public void run() {
keepRunning = false;
LOGGER.debug("The shutdown hook was engaged. Setting keepRunnning to false.");
try {
// Is this appropriate?
mainThread.join();
} catch (InterruptedException e) {
// handle exception here
}
}
});
The shutdown hook is from typical docs example. It doesn't seem to work well with the Guava services pattern since the service itself is running on a different thread.
My service has a polling loop in the runOneIteration() logic. I want it to complete it's current task at hand and then shutdown gracefully when is sees that the keepRunning is now false since the Shutdown hook was engaged some time in the recent past when it was busy with its current iteration.
Any ideas how this can be done gracefully (complete current iteration and then shutdown)?
Wouldn't you just call stopAndWait()?
Runtime.getRuntime().addShutdownHook(new Thread() {
#Override
public void run() {
service.stopAsync().awaitTerminated(60, TimeUnit.SECONDS);
}
});

Custom Functions in Thread

I have a simple Question:
I have a Thread named rlMF. I created it this way:
public Thread rlMF = new Thread(new Runnable() {
public void run() {
reloadMissingFiles();
stopTh();
}
public void stopTh() {
activityStopped = true;
}
});
Now i want to call the stopTh Function from outer Thread. Why can't i simply call rlMF.stopTh(); and what can i do else?
Example:
protected void onPause() {
Log.d("Info", "destroying...");
activityStopped = true;
rlMF.stopTh();
super.onPause();
}
Is not working...
Because the interface accessible is from Thread. In order to have you method accessible from out, you need to specify a type that exposes this method.
And if you take a look carefully the method is implemented in the instance of Runnable. Not even in Thread.
You could have something like this if you really need to access the Runnable object:
class MyRunnable implements Runnable {
public void run() {
...
}
public void fooBar() {
...
}
}
public void someMethod() {
MyRunnable myRunnable = new MyRunnable();
Thread thread = new Thread(myRunnable);
...
myRunnable.fooBar();
...
}
An example for Francisco approach, besides what you are trying to achieve. Maybe this can point you in the right direction
public class CustomRun implements Runnable {
public void run() {
reloadMissingFiles();
stopTh();
}
public void stopTh() {
activityStopped = true;
}
}
In your Code
// start thread with custom runner
CustomRun runner = new CustomRun();
new Thread(runner).start();
// call your stopTh method on CustomRun class
protected void onPause() {
Log.d("Info", "destroying...");
activityStopped = true;
runner.stopTh();
super.onPause();
}
Your goal is to interrupt the thread from onPause. There are several ways to do it, but essentially, you will need to include some interruptibility in reloadMissingFiles.
Option 1
You can use a boolean flag like you did - you need to declare it as volatile to make sure the changes are visible across threads:
private volatile boolean activityStopped = false;
public void reloadMissingFiles() {
while (!activityStopped) {
//load small chunks so that the activityStopped flag is checked regularly
}
}
public Thread rlMF = new Thread(new Runnable() {
public void run() {
reloadMissingFiles(); //will exit soon after activityStopped has been set to false
}
});
protected void onPause() {
//This will stop the thread fairly soon if the while loop in
//reloadMissingFiles is fast enough
activityStopped = true;
super.onPause();
}
Option 2 (better approach)
I don't know what you do in reloadMissingFiles, but I suppose it is some sort of I/O operations, which are generally interruptible. You can then have an interruption policy where you stop as soon as an InterruptedException is caught:
public void reloadMissingFiles() {
try {
//use I/O methods that can be interrupted
} catch (InterruptedException e) {
//cleanup specific stuff (for example undo the operation you started
//if you don't have time to complete it
//then let the finally block clean the mess
} finally {
//cleanup (close the files, database connection or whatever needs to be cleaned
}
}
public Thread rlMF = new Thread(new Runnable() {
public void run() {
reloadMissingFiles(); //will exit when interrupted
}
});
protected void onPause() {
runner.interrupt(); //sends an interruption signal to the I/O operations
super.onPause();
}
Note: you can also read this article for a more in depth version of it.

Categories

Resources