Java: Cancel REST service method execution - java

I expose an Stateless EJB as a REST service. In my POST-method, I call
Result r = longRunningBusinessMethod();
//return data
How do I go about making it possible to cancel the execution of longRunningBusinessMethod() from the client side?
I thought about creating a thread for the method, and keeping all executing threads in a hashtable together with an id, so that the user can POST his id to terminate the thread. But I am sure there must be a better solution.
Any help will be appreciated.

Interrupting working threads is always tricky and not recommended in general. One way around is to modify running business method to ask whether it should complete its execution. For instance:
public void longRunningBusinessMethod(JobContext context){
while(someCondition) {
if(shouldInterrupt(context)){
log.info("Interrupting longRunningBusinessMethod");
...
<close all the resources and terminate the job>
}
}
}
TheshouldInterrupt(context) will take job context with Job ID in it and will ask DB or Cache whether it should be interrupted. Then it's easy to change 'shouldInterrup' value in DB or Cache for this particular job via the REST API.

I think the rough design of "keeping a table of IDs" is a good starting place. Instead of terminating the thread externally, I'd probably use an ExecutorService with a thread pool, and then keep a Map<ID, Future>, so you can cancel the future. (Also making sure that each future removes itself from the map as it completes successfully or exceptionally.)
You'll also have to implement the longRunningBusinessMethod so that it contains enough places where it checks to see if it's been interrupted - canceling a future only sets the interrupted flag on the thread, it doesn't actually stop the code from executing. If your long-running methods already throw InterruptedException, it's fine as-is. Otherwise, you'll need to either add in some dummy calls, like Thread.sleep(1), or manually check Thread.interrupted() every so often, and throw the InterruptedException yourself.

Related

How can I gracefully end execution in a java executor without returning or using an exception?

I have codebase that calls a black box, that in turn calls other code I have control of, call it thing.innerMethod(). The code in the black box needs to execute in a different thread than the code that calls it, so I have decided to use an executor:
Future<String> bbFuture = executorService.submit(() -> {
return blackBox.doStuff(thing);});
If the execution takes too long, the user might call another endpoint that ultimately calls bbFuture.cancel(), triggering a CancellationException in the thread with the future and an InterruptedException in the thread running inside the executor.
The problem is that when the InterruptedException propagates into the black box, it catches it and logs it a stack trace, and raises false alarms. I don't need to catch every InterruptedException, but I know a place I could put a catch that would get probably 90% of them. The problem is I don't really have a good way to stop execution without returning from the function, and any partial or dummy result would probably trigger another exception. I know I could use Thread.currentThread().stop(), but stop() is deprecated.
How can I stop execution inside a java executor without returning or throwing an exception?
You can choose to run the task user wants to cancel by wrapping the future into another object which implements cancel() request and do not delegate the user given cancel request to the underlying future instance. In this case, the task will run as normal. (Trick user that the task cancelled but run in background and do not care the result of the task -- If the task has side-effect, this might not be desirable) -- will use computing resources.
If you want the task to be responsive to interruption, then you should use the regular way of cancelling a task, namely notify the task that it should no longer continue by future.cancel() and the task you are notifying should be coded in a way that detects interruptions and clears any state required and return. (return something like an empty result, a special result etc.)
NOTE: future.cancel() sets a specific boolean field in Thread class. Some blocking library functions throws InterruptedException in the entry before doing something. For instance, Thread.sleep function might look to see if the boolean flag is set and throw InterruptedException without waiting, or it might wait and somehow detect the cancellation request before waiting to the end and throw InterruptedException. Or it might not detect at all. In this case, you should check regulary through out the task that if the task cancelled. [ using Thread.currentThread().isInterrupted()]

Telling the asynchronous job to wait in Java

I have a situation where sometimes (not always) my asynchronous job is not able to process results by the time needed and I have to return some kind of message to the client saying that his request is still being prepared by checking for it in the database.
The request and creating necessary object for it is handled in one database Transaction, the asynchronous process is handled in the different Transaction. I am using ScheduledThreadPoolExecutor by passing the runnable instance to the execute method.
The problems that sometimes the client makes a request and while the his browser is loading my asynchronous job is able to prepare the necessary data for it, but sometimes it isn't.
So my question is: Is there anyway I can tell asynchronous job to wait until the data is ready?
I am afraid that using just a Runnable instance you are not be able to tell the process to wait unless you sleep the Thread for sometime or looping and keep asking for the results which both are bad ideas.
In order to make this happen correctly, you should use a FutureTask for this by passing Callable instance to it's constructor. By overriding your call() method you should tell you transactional handler to do the job.
You also need to have some kind of a task manager which will add the task to the queue and creates a thread pool which takes and processes those tasks. For the queue purpose I would suggest to use for e.g.: LinkedBlockingDeque which accepts the generic type of FutureTask.
Also you should have a map of future tasks mapped by their name or something which takes the FutureTask as a value. In terms of waiting for the results when your Thread is processed the given FutureTask already you have to immediately remove it from the futures map. Then when your client requests you should check: if the futures map contains the task get the FutureTask from it and call futureTask.get() on it. This will wait until the task is finished.
This is just approach with which I would go. Hope this helps.

Regarding stopwatch or timer or some other utility

I have a requirement to start a task..Now many threads can start this task and this task normally takes 4-5 seconds to complete. I want to prevent the starting of a task if this task has been already started by some other thread.
In order to implement this requirement, I am thinking of starting a timer or stopwatch in a different thread whenever the task is started by some thread. Now when the timer times out after a configured time-interval, another thread can starts a task.
So, is starting a timer or stopwatch in a different thread to see if the particular time has been reached is a good solution?Is there any good alternative for it?
If I understand correctly, this is a bad idea. Basically you are assumming your job will never run for more than 5 seconds so if the watch tells you that some job was started less than 5 seconds ago, you won't start another one. This is very unreliable.
Instead create some sort of flag that you set when job starts and unset when ends. AtomicBoolean is perfect for that:
private AtomicBoolean flag = new AtomicBoolean();
//...
if(!flag.getAndSet(true)) {
try {
//do your work
} finally {
flag.set(false);
}
} else {
//Already running
}
If you want another job to wait for the previous one instead of simply being discarded, just surround your task with synchronized or use some different locking mechanism.
Note: if your jobs are distributed you will need a distributed locking mechanism, like a databasse or hazelcast.
If you are trying to do this in java then you can consider using a synchronized block on the Object Oriented approach on JAVA.
So any task that you want to make sure is done by one thread at a time then make a class and a synchronized method in that class, also make sure you all the threads share the same object of the class and call this method in which they want to perform the task.
For Example
Class SyncTask{
synchronized void task1(){
//Perform your task here
}
}
Create the object of this class once during the lifetime of your application and then use this same object across all the threads and let them call this method to which you want to perform your task.
In the case of multiple threads invoking this method at the same time. JVM will take care of the sequence and if one thread is already performing a task, the others calling it will wait for the first one to finish.
In this way you will be sure that only on thread is performing the task at any given time.
I hope this helps.
If you want to schedule task the framework of choice is usually something similar to Quartz. It should allow you to do what you need and more. Regarding the issue of non running concurrent tasks, I would recommend you take a look at this previous SO post which should point you in the right direction.

Killing a thread in java android

I have an application where i need to call 3 methods in 3 seperate threads and kill them afterwards. According to the Javadoc i noticed that thread stop() and even destroy() has been deprecated. its like I start one thread after the other and then kill similarly one after the other. Is there a particular way to kill the threads because I cant use the deprecated methods
Any help much appreciated.
Thanks again
You don't kill threads. You call Thread.interrupt(), and then react to the interrupted status or InterruptedException within the thread that's being interrupted. Or, you use a volatile flag. See the official documentation for background and more info.
Even better, use a thread pool / executor instead of raw threads, as suggested in comments.
Terminating a rogue thread in a way that works every time everywhere is pretty much impossible.
If you can control the source code of the running threads, you must add a method with which you can stop the thread when you need to. Basically this method changes a boolean variable and the thread checks that value periodically to see whether or not it can continue.
public class MyTask implements Runnable {
// Set this to true when thread must stop.
private boolean mStopRequested = false;
public void run() {
while (mStopRequested == false) {
// ...
}
}
}
If you call a 3rd party libraries that do not provide such a method, then you are out of luck and have to resort to ugly kludges. Once I had to kill a long running 3rd party library call by deleting a file that was accessed by the library (it threw a FileNotFoundException and exited). And that only worked on Unix systems.
Your mileage will vary.
Use join method until the receiver finishes its execution and dies or the specified timeout expires, whatever happens first.
thread1.join(1);
thread2.join(2);
thread3.join(3);
You must handle the exception.

How to stop a thread after some time in java?

In my android app I am having a thread in which I fetch data from a web service.
So normally it works well, but sometimes if the connection is too slow it kind of hangs.
So is there any way by which I can set some time say 1 min, and if the thread process is not
completed in 1 min. then I would like to stop this thread and display a message to the user that connection is weak/slow and try later.
Please help !!
This is a bad idea. The Thread.stop method is deprecated for good reasons.
I suggest you do the following: Set the network time-outs according to your preferences. If this doesn't help, I suggest that you simply throw away the reference to the thread, (ignore it, let it die out and get garbage collected) and respond with a nice message about network failure. You can very well start a new thread for trying again.
I don't know whether it is supported in Android, but this is exactly what the Future objects returned from an ExecutorService are supposed to do for you. In particular, the cancel(boolean) method can be used to interrupt the task if it has started but not finished.
The tasks should be written to be aware that they may be interrupted, and abort cleanly if they have been. Most of the framework IO methods can be interrupted, so you just need to worry about your own code.
you can use the method : Thread.interrupt();
the method Thread.stop() is deprecated
Create a stop method like this, and call interrupt subsequently.
public void stop() {
Thread currentThread= someThread;
someThread= null;
currentThread.interrupt();
}

Categories

Resources