I am writing an enterprise Java application that uses asynchronous EJB 3.1 methods to execute a number of tasks in parallel. To support cancelling a long running task I have been attempting to use the Future interface.
Unfortunately calling future.cancel(true)
from the client application appears to have no effect on the session context of the bean executing the task, despite the fact that the cancel call is returning true
.
I have a simple interface:
public interface AsyncInterface
{
Future<Integer> run() throws Exception;
}
With a bean implementation as follows:
@Stateless
@Remote(AsyncInterface.class)
public class AsyncBean
{
@Resource SessionContext myContext;
@Asynchronous
public Future<Integer> run() throws Exception
{
Integer result = 0;
System.out.println("Running AsyncBean");
while(myContext.wasCancelCalled() == false)
{
Thread.sleep(2000);
System.out.println("Working");
}
System.out.println("AsyncBean cancelled");
return new AsyncResult<Integer>(result);
}
}
The client code is straight forward:
InitialContext ctx = new InitialContext();
AsyncInterface async = (AsyncInterface)ctx.lookup("AsyncBean/remote");
Future<Integer> future = async.run();
if( future.cancel(true) )
{
System.out.println("future.cancel() returned true");
}
else
{
System.out.println("future.cancel() returned false");
}
The output from the bean is an endless stream of "Working"; it never detects the cancellation.
In case it's relevant, I'm running the application on JBoss Application Server 6.0.0. I haven't located much sample code using the cancel feature of the Future interface, so I'm wondering if I am using Future correctly. Does this usage look correct? Are there better options for cancelling an asynchronous EJB method call?
Answering my own question - I've found out that cancallation of asynchronous requests is not supported in JBoss AS 6.0.0.
As an alternative I've refactored the code to use JMS request/response style messaging.
A message driven bean is used to execute an asynchronous operation. The message driven bean creates a temporary queue and returns the queue to the caller via JMS. This is achieved by utilising the replyTo field of JMS messages.
The message driven bean then periodically checks the temporary queue for a cancellation message.
This is more complicated than the @Asynchronous version but it works on JBoss AS 6.0.0.
You must return
a Future
type of object, instead of null
. By the way, are you not getting a NPE? I would expect one, with your code in question.
Furthermore, cancel()
should not be called. See the docs here. By the way, its not just cancel()
method which should not be called, no instance method should be called, according to the docs. Which begs the question that why the heck then a method should return AsyncResult
. I simply have no idea, may be its there for future use. But the class level comments are suggesting that all the methods are there for convenience to provide the result to the container.
Hence, I am not sure whether cancelling the asynchronous EJB call is possible at all or not yet.
[Edited after a little research]
Try this implementation,
@Stateless
@Remote(AsyncInterface.class)
public class AsyncBean
{
@Resource SessionContext myContext;
@Asynchronous
public Integer run() throws Exception
{
Integer result = 0;
System.out.println("Running AsyncBean");
while(myContext.wasCancelCalled() == false)
{
Thread.sleep(2000);
System.out.println("Working");
}
System.out.println("AsyncBean cancelled");
return result;
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With