Why my #Async Future<T> blocks? - java

I have 2 Synchronous methods, the following one does not block.
#RequestMapping("/send1")
#Async
public Future<Boolean> sendMail() throws InterruptedException {
System.out.println("sending mail 1..-"
+ Thread.currentThread().getName());
Thread.sleep(1000 * 16);
System.out.println("sending mail 1 completed");
return new AsyncResult<Boolean>(true);
}
But the following one blocks.
#RequestMapping("/send3")
public void callAsyn3() throws InterruptedException, ExecutionException {
Future<Boolean> go = sendMail3("test");
}
#Async
public Future<Boolean> sendMail3(String msg) throws InterruptedException {
boolean acceptedYet = false;
Thread.sleep(1000 * 12);
if (!msg.equalsIgnoreCase("")) {
acceptedYet = true;
}
return new AsyncResult<>(acceptedYet);
}
They are in the same controller class, Why such different behavior?

In the second case you call internally method. so the #Async is ignored (not proxyed method called).
There are two ways to fix
The first one is to ntroduce a separate bean (e.g. MyService) and move the annotated with #Async method there.
The second way is Autowire the controller to itself
#Controller
public class MyController {
#Autowired
private MyController myController;
#RequestMapping("/send3")
public void callAsyn3() throws InterruptedException, ExecutionException {
Future<Boolean> go = myController.sendMail3("test");
}
#Async
public Future<Boolean> sendMail3(String msg) throws InterruptedException {
boolean acceptedYet = false;
Thread.sleep(1000 * 12);
if (!msg.equalsIgnoreCase("")) {
acceptedYet = true;
}
return new AsyncResult<>(acceptedYet);
}

Calling method in the same class do not pass through the proxy. So you can not use a method with #Async in the same class and make calls asynchronous.
We can create another service and write the #Async method there. Something like this
#Service
public class MyService {
#Async
public Future<Boolean> sendMail3(String msg) throws InterruptedException {
boolean acceptedYet = false;
Thread.sleep(1000 * 12);
if (!msg.equalsIgnoreCase("")) {
acceptedYet = true;
}
return new AsyncResult<>(acceptedYet);
}
}
This will run asynchronously ( non-blocking ).
If you want to do this in the same controller, you can submit it manually to some thread pool.

you have self-invocation , call method sendMail3 from method callAsyn3 directly. it doesn't work because it bypasses the proxy and calls the underlying method directly.
simple fix - you should get contoller from context and call callAsyn3 from this instance.
normal fix - create new service - asyncSendMailComponent/Service, move sendMail3 into asyncSendMailComponent , inject asyncSendMailComponent into you controller and call sendMail3
in controller :
#Autowired
private AsyncSendMailComponent asyncSendMailComponent;
#RequestMapping("/send3")
public void callAsyn3() throws InterruptedException, ExecutionException {
Future<Boolean> go = asyncSendMailComponent.sendMail3(msg)
}
Async service
#Service
pubclic class AsyncSendMailComponent {
#Async
public Future<Boolean> sendMail3(String msg) throws InterruptedException {
boolean acceptedYet = false;
Thread.sleep(1000 * 12);
if (!msg.equalsIgnoreCase("")) {
acceptedYet = true;
}
return new AsyncResult<>(acceptedYet);
}
}

Related

Avoid blocking method to make the code asynchronous

How can I change this code to get rid of thread blocking? Here .get() blocks the thread to receive the result from the future. But can I absolutely avoid blocking? Something like - one thread sends the requests, and the other one receives responses and implements some code. To make it fully asynchronous.
I tried to use CompletableFuture, but couldn't really understand it.
Tried to make a callback method, but wasn't successful as well.
byte[] sendRequest(JSONObject jsonObject, String username, String password) throws IOException, ExecutionException, InterruptedException {
try (AsyncHttpClient client = new AsyncHttpClient()) {
String userPassword;
if (username != null && password != null) {
userPassword = username + ":" + password;
} else {
throw new NullPointerException("Нет логина и/или пароля.");
}
Future future = client.preparePost(apiUrl)
.addHeader("Content-Type", "application/json")
.addHeader("Authorization", "Basic " + DatatypeConverter.printBase64Binary(userPassword.getBytes()))
.setBody(jsonObject.toString().getBytes())
.execute(getHandler());
String response = (String) future.get();
return response.getBytes();
}
}
private AsyncCompletionHandler<String> getHandler() throws IOException {
return new AsyncCompletionHandler<String>() {
#Override
public String onCompleted(Response response) throws IOException {
return response.getResponseBody();
}
#Override
public void onThrowable(Throwable t) {
}
};
}
What I expect:
The program sends a request in the main thread.
Then there is a kind of a callback that waits for a response in an
alternative thread.
Still, the program continues working in the main thread - it goes on with sending more requests.
When the response from the server comes, the callback from the
alternative thread catches it and processes in some way, but it
doesn't correspond with the main thread
You should run your async task in new thread (preferably using ExecutorService or CompletableFuture). Pass CallbackHandler to the Runnable/Callable tasks and once the invocation is complete invoke handler methods.
Alternatively, if all you're worried about is handling async http requests, I'd suggest to not reinvent the wheel and instead use existing solutions. Example of async http client
For other use cases, you can follow the following example.
import java.util.*;
import java.lang.*;
import java.io.*;
class Ideone {
public static void main (String[] args) throws java.lang.Exception {
for (int i=0; i<10; i++) {
new Thread(new MyRunnable(new CallbackHandler())).start();
}
}
static class MyRunnable implements Runnable {
CallbackHandler handler;
public MyRunnable(CallbackHandler handler) {
this.handler = handler;
}
public void run() {
try {
Thread.sleep(100);
} catch(Exception e) {
} finally {
Random r = new Random();
if (r.nextBoolean()) {
handler.onSuccess();
} else {
handler.onError();
}
}
}
}
static class CallbackHandler {
public void onSuccess() {
System.out.println("Success");
}
public void onError() {
System.out.println("Error");
}
}
}

How to stub asynchronous calls with mockito?

Suppose I have a two classes that work together to execute a callable like this:
public class blah {
#Autowired
private ExecutorServiceUtil executorServiceUtil;
#Autowired
private RestTemplate restClient;
public SomeReturnType getDepositTransactions(HttpHeaders httpHeaders) {
ExecutorService executor = executorServiceUtil.createExecuter();
try {
DepositTransactionsAsyncResponse asyncResponse = getPersonalCollectionAsyncResponse( httpHeaders, executor);
// do some processing
// return appropriate return type
}finally {
executorServiceUtil.shutDownExecutor(executor);
}
}
Future<ResponseEntity<PersonalCollectionResponse>> getPersonalCollectionAsyncResponse( HttpHeaders httpHeaders, ExecutorService executor) {
PersonalCollectionRequest personalCollectionRequest = getpersonalCollectionRequest(); // getPersonalCollectionRequest populates the request appropriately
return executor.submit(() -> restClient.exchange(personalCollectionRequest, httpHeaders, PersonalCollectionResponse.class));
}
}
public class ExecutorServiceUtil {
private static Logger log = LoggerFactory.getLogger(ExecutorServiceUtil.class);
public ExecutorService createExecuter() {
return Executors.newCachedThreadPool();
}
public void shutDownExecutor(ExecutorService executor) {
try {
executor.shutdown();
executor.awaitTermination(5, TimeUnit.SECONDS);
}
catch (InterruptedException e) {
log.error("Tasks were interrupted");
}
finally {
if (!executor.isTerminated()) {
log.error("Cancel non-finished tasks");
}
executor.shutdownNow();
}
}
}
How can I use Mockito to stub the a response and return it immediately?
I've tried the below but my innovcation.args() returns [null]
PowerMockito.when(executor.submit(Matchers.<Callable<ResponseEntity<OrxPendingPostedTrxCollectionResponseV3>>> any())).thenAnswer(new Answer<FutureTask<ResponseEntity<OrxPendingPostedTrxCollectionResponseV3>>>() {
#Override
public FutureTask<ResponseEntity<OrxPendingPostedTrxCollectionResponseV3>> answer(InvocationOnMock invocation) throws Throwable {
Object [] args = invocation.getArguments();
Callable<ResponseEntity<OrxPendingPostedTrxCollectionResponseV3>> callable = (Callable<ResponseEntity<OrxPendingPostedTrxCollectionResponseV3>>) args[0];
callable.call();
return null;
}
});
You do that by not using your ExecutorServiceUtil in your test code. What I mean is: you provide a mock of that util class to your production code!
And that mock does return a "same thread executor service"; instead of a "real service" (based on a thread pool). Writing such a same-thread-executor is actually straight forward - see here.
In other words: you want two different unit tests here:
You write unit tests for your ExecutorServiceUtil class in isolation; make sure it does the thing it is supposed to do (where I think: checking that it returns a non-null ExecutorService is almost good enough!)
You write unit tests for your blah class ... that use a mocked service. And all of a sudden, all your problems around "it is async" go away; because the "async" part vanishes in thin air.

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);
}

Why is my Spring #Async bean method not being executed asychronously?

I have a Springboot application and I'm trying to execute an asynchronous method on a bean class inside a controller method. The problem is that my #Async method is not being executed asynchronously. Execution is halted until the method completes.
Can anyone tell me what I'm missing?
Here is my application class:
#SpringBootApplication
#EnableAsync
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
#Bean
public EmbeddedServletContainerFactory servletContainer() {
TomcatEmbeddedServletContainerFactory factory = new TomcatEmbeddedServletContainerFactory();
factory.addConnectorCustomizers(new TomcatConnectorCustomizer() {
#Override
public void customize(Connector connector) {
connector.setPort(9000);
connector.setAsyncTimeout(60000);
}
});
return factory;
}
}
Here is my bean class:
public class LongProcess {
#Async
public Future<String> call() {
try {
System.out.println("Sleeping now...");
Thread.sleep(10000);
return new AsyncResult<String>("Hey");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return null;
}
}
}
My configuration class:
#Configuration
#EnableAsync
public class LongProcessConfiguration implements AsyncConfigurer {
#Bean
public LongProcess longProcessBean() {
return new LongProcess();
}
#Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
taskExecutor.setMaxPoolSize(10);
taskExecutor.setThreadNamePrefix("LULExecutor-");
taskExecutor.initialize();
return taskExecutor;
}
#Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return new SimpleAsyncUncaughtExceptionHandler();
}
}
My controller method:
#RequestMapping("/utilities/longProcess")
public String longProcess() {
System.out.println("Starting long process...");
CsvFileDifferConfiguration context = new CsvFileDifferConfiguration();
LongProcess process = context.longProcessBean();
Future<String> result = process.call();
System.out.println("Done!");
return "{success: 1}";
}
This request unfortunately does not return immediately (I don't care about the result). The method is called successfully, but not in the background. Any idea what I might be missing?
As a test, if I change the controller method to wait for the result, the wait block is never entered:
#RequestMapping("/utilities/longProcess")
public String longProcess() throws InterruptedException {
System.out.println("Starting long process...");
CsvFileDifferConfiguration context = new CsvFileDifferConfiguration();
LongProcess process = context.longProcessBean();
Future<String> result = process.call();
while (!(result.isDone())) {
Thread.sleep(1); //10-millisecond pause between each check
System.out.println("Waiting for Long Process...");
}
System.out.println("Done!");
return "{success: 1}";
}
You have a mistake for the CDI usage.
If you manage your object using Spring Container you have to get deal just with ApplicationContext or its abilities like #Autowired.
The code
CsvFileDifferConfiguration context = new CsvFileDifferConfiguration();
is wrong.
Since you define your LongProcess as a #Bean you can just inject it to your #Controller:
#Autowired
privete LongProcess process;
and use it as before.
Using objects directly (e.g. new) loses the dependency injection features.
Read more Spring Docs, please.

How to assert after a Mockito mock object invokes a void method in another thread?

The constructor of the object under test starts a new thread that waits to take() from a queue, and when it finally does take it calls a void on the mock with the data. How do I make an assert that the queue is empty after the void is called on the mock?
CUT:
public class MsgHandler {
LinkedBlockingQueue<String> outQueue = ...
public MsgHandler(Connection conn, ...) {
new Thread(() -> {
while (true) try {
conn.async(outQueue.take()); //void method call here
} catch (...) {...}
}).start();
...
}
}
Test:
#Test
public void testOutboundMessageSentImmediately() throws Exception{
Connection conn = mock(Connection.class); //create mock Connection
MsgHandler handler = new MsgHandler(conn,...); //create CUT
doNothing().when(conn).async("query");
outQueue.add("query")
assertTrue(outQueue.isEmpty()); //how do I do this after the when?
}
You should be able to use awaitility to test asynchronous code. This could be something like
await().atMost(5, SECONDS).untilCall(outQueue::isEmpty, is(true));

Categories

Resources