App using Retrofit 2 waits for one minute before exiting - java

I'm using Retrofit 2 to make asynchronous calls. The problem is that after the response is received (onResponse is done with its work), the application still waits for 60 seconds before quitting.
This is the essential bit:
Call<MyResponse> call = client.resource();
call.enqueue(new Callback<MyResponse>() {
#Override
public void onResponse(Call<MyResponse> c, Response<MyResponse> response) {
// This gets called in a few milliseconds
}
#Override
public void onFailure(Call<MydResponse> c, Throwable t) {
}
});
It looks like some ThreadPoolExecutor is waiting to time out (maybe in okhttp). But shouldn't the pool become free after the response is received as there is nothing else to process?
Is this a bug, am I misusing it, or is it normal to wait for 60 seconds when there is in fact nothing else to process?
How do I make the application exit right after the onResponse is done?

Related

How to keep the calling function thread on hold till the time all the threads processing gets completed?

I am working on a scenario as described below:
We are consuming messages from kafka, and each message received should be processed in parallel, given that I have to keep on hold the main( or calling) thread until all the messages received(1 message-1 thread) are done with processing.
Given that number of messages is known and is available from the kafka message headers.
Once the processing is completed for all the threads, only after that the calling thread should proceed ahead.
I tried using CountDownLatch with the count as number of messages going to be received, but using this, it is keeping the main thread on hold, and not allowing to consume the next messages.
Is there anyway, by which this can be achieved ?
Code Snippet:
class MessageHandler{
#Autowired private ProcessorAsync processorAsync;
public void handle()
{
CountdownLatch countdown = new CountdownLatch(noOfMessages);
CompletableFuture<Void> future = processorAsync.processMessage(message,countdown);
countdown.await();
if(future.isDone())
{//post msg processing methods/api calls
m1();
m2();
}
}
}
class ProcessorAsync
{
#Async("customThreadPool") // max 20 threads
public CompletableFuture<Void> processMessage(Message msg, CountdownLatch countdown)
{
//DB update statements
// .
countdown.countdown();
return CompletableFuture.allOf();
}
}

Handling on Jersey (JAX-RS) on XMLHttpRequest abort

I'm using Jersey for the application's REST API, consider the function below
#POST
public String writeSomething() {
someVeryIntensiveTaskWhichTaking("5 seconds");
Log.info("get request fulfilled") // don't want the logging to happen if user cancelled on UI
return "ok";
}
Assume this POST request is doing some intensive task and might takes up to 5 seconds. Then on the UI, the user decided to cancel the POST request via XMLHttpRequest.abort() at 2 second,
is there any way to track this abortion and prevent some action being done? something like checking IsClientConnected?
Update #1
Thanks to peeskillet's tips, but i still unable to get the callback being triggered upon the XHR's abortion. The below is my code
#POST
public String writeSomething(#Suspended final AsyncResponse asyncResponse) {
asyncResponse.register(new ConnectionCallback() {
public void onDisconnect(AsyncResponse asyncResponse) {
System.out.println("This is canceled, do whatever you want"); // this is not triggered after XHR aborted
}
});
someVeryIntensiveAsynTaskWhichTaking("5 seconds", asyncResponse); // this asyn function will trigger asyncResponse.resume() upon completion
}

Jersey/JAX-RS 2 AsyncResponse - how to keep track of current long-polling callers

My goal is to support long-polling for multiple web service callers, and to keep track of which callers are currently "parked" on a long poll (i.e., connected). By "long polling," I mean that a caller calls a web service and the server (the web service) does not return immediately, but keeps the caller waiting for some preset period of time (an hour in my application), or returns sooner if the server has a message to send to the caller (in which case the server returns the message by calling asyncResponse.resume("MESSAGE")).
I'll break this into two questions.
First question: is this a reasonable way to "park" the callers who are long-polling?
#GET
#Produces(MediaType.TEXT_PLAIN)
#ManagedAsync
#Path("/poll/{id}")
public Response poller(#Suspended final AsyncResponse asyncResponse, #PathParam("id") String callerId) {
// add this asyncResponse to a HashMap that is persisted across web service calls by Jersey.
// other application components that may have a message to send to a caller will look up the
// caller by callerId in this HashMap and call resume() on its asyncResponse.
callerIdAsyncResponseHashMap.put(callerId, asyncResponse);
asyncResponse.setTimeout(3600, TimeUnit.SECONDS);
asyncResponse.setTimeoutHandler(new TimeoutHandler() {
#Override
public void handleTimeout(AsyncResponse asyncResponse) {
asyncResponse.resume(Response.ok("TIMEOUT").build());
}
});
return Response.ok("COMPLETE").build();
}
This works fine. I'm just not sure if it's following best practices. It seems odd to have the "return Response..." line at the end of the method. This line is executed when the caller first connects, but, as I understand it, the "COMPLETE" result is never actually returned to the caller. The caller either gets "TIMEOUT" response or some other response message sent by the server via asyncResponse.resume(), when the server needs to notify the caller of an event.
Second question: my current challenge is to accurately reflect the population of currently-polling callers in the HashMap. When a caller stops polling, I need to remove its entry from the HashMap. A caller can leave for three reasons: 1) the 3600 seconds elapse and so it times out, 2) another application component looks up the caller in the HashMap and calls asyncResponse.resume("MESSAGE"), and 3) the HTTP connection is broken for some reason, such as somebody turning off the computer running the client application.
So, JAX-RS has two callbacks I can register to be notified of connections ending: CompletionCallback (for my end-poll reasons #1 and #2 above), and ConnectionCallback (for my end-poll reason #3 above).
I can add these to my web service method like this:
#GET
#Produces(MediaType.TEXT_PLAIN)
#ManagedAsync
#Path("/poll/{id}")
public Response poller(#Suspended final AsyncResponse asyncResponse, #PathParam("id") String callerId) {
asyncResponse.register(new CompletionCallback() {
#Override
public void onComplete(Throwable throwable) {
//?
}
});
asyncResponse.register(new ConnectionCallback() {
#Override
public void onDisconnect(AsyncResponse disconnected) {
//?
}
});
// add this asyncResponse to a HashMap that is persisted across web service calls by Jersey.
// other application components that may have a message to send to a caller will look up the
// caller by callerId in this HashMap and call resume() on its asyncResponse.
callerIdAsyncResponseHashMap.put(callerId, asyncResponse);
asyncResponse.setTimeout(3600, TimeUnit.SECONDS);
asyncResponse.setTimeoutHandler(new TimeoutHandler() {
#Override
public void handleTimeout(AsyncResponse asyncResponse) {
asyncResponse.resume(Response.ok("TIMEOUT").build());
}
});
return Response.ok("COMPLETE").build();
}
The challenge, as I said, is to use these two callbacks to remove no-longer-polling callers from the HashMap. The ConnectionCallback is actually the easier of the two. Since it receives an asyncResponse instance as a parameter, I can use that to remove the corresponding entry from the HashMap, like this:
asyncResponse.register(new ConnectionCallback() {
#Override
public void onDisconnect(AsyncResponse disconnected) {
Iterator<Map.Entry<String, AsyncResponse>> iterator = callerIdAsyncResponseHashMap.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry<String, AsyncResponse> entry = iterator.next();
if (entry.getValue().equals(disconnected)) {
iterator.remove();
break;
}
}
}
});
For the CompletionCallback, though, since the asyncResponse is already done or cancelled at the time the callback is triggered, no asyncResponse parameter is passed in. As a result, it seems the only solution is to run through the HashMap entries checking for done/cancelled ones and removing them, like the following. (Note that I don't need to know whether a caller left because resume() was called or because it timed out, so I don't look at the "throwable" parameter).
asyncResponse.register(new CompletionCallback() {
#Override
public void onComplete(Throwable throwable) {
Iterator<Map.Entry<String, AsyncResponse>> iterator = callerIdAsyncResponseHashMap.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry<String, AsyncResponse> entry = iterator.next();
if (entry.getValue().isDone() || entry.getValue().isCancelled()) {
iterator.remove();
}
}
}
});
Any feedback would be appreciated. Does this approach seem reasonable? Is there a better or more Jersey/JAX-RS way to do it?
Your poller() method does not need to return a Response in order to participate in asynchronous processing. It can return void. If you are doing anything complex in the poller however you should consider wrapping the whole method in a try/catch block that resumes your AsyncResponse object with the exception to ensure that any RuntimeExceptions or other unchecked Throwables are not lost. Logging these exceptions in the catch block here also seems like a good idea.
I'm currently researching the question of how to reliably catch an asynchronous request being cancelled by the client and have read at one question that suggests the mechanism isn't working for the questioner[1]. I'll leave it to others to fill out this information for the moment.
[1] AsyncResponse ConnectionCallback does not fire in Jersey

Android BLE: onCharacteristicRead() appears to be blocked by thread

I'm implementing a series of characteristic reads against a BLE device. Because readCharacteristic() executes asynchronously, and because we have to wait until it completes before issuing another "read" call, I used a lock to wait() and then in 'onCharacteristicRead() I notify() the lock to get things going again.
When I wait() after calling readCharacteristic(), I never get a call to onCharacteristicRead(). If I don't wait(), then I do get a call to onCharacteristicRead() and the correct value is reported.
Here is the relevant code that seems to block the callback to onCharacteristicRead():
private void doRead() {
//....internal accounting stuff up here....
characteristic = mGatt.getService(mCurrServiceUUID).getCharacteristic(mCurrCharacteristicUUID);
isReading = mGatt.readCharacteristic(characteristic);
showToast("Is reading in progress? " + isReading);
showToast("On thread: " + Thread.currentThread().getName());
// Wait for read to complete before continuing.
while (isReading) {
synchronized (readLock) {
try {
readLock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
showToast("onCharacteristicRead()");
showToast("On thread: " + Thread.currentThread().getName());
byte[] value = characteristic.getValue();
StringBuilder sb = new StringBuilder();
for (byte b : value) {
sb.append(String.format("%02X", b));
}
showToast("Read characteristic value: " + sb.toString());
synchronized (readLock) {
isReading = false;
readLock.notifyAll();
}
}
If I simply remove the while() statement above, I successfully get the read callback. Of course, that prevents me from waiting to do further reads, so I can't move forward without waiting.
Given that the readCharacteristic() is asynchronous, why would execution of the calling thread have anything to do with the ability to actually do the read, or the ability to call the callback?
To make things more confusing, I show a toast which identifies the thread when I call readCharacteristic(), as well as when onCharacteristicRead() is invoked. These 2 threads have different names. I thought that maybe the callback was being invoked on the calling thread for some reason, but that doesn't appear to be the case. So what is going on here with the threading?
The problem here appears to be an obscure issue with threading and it can't be seen in my original post because I didn't post enough of the call history to see it. I will explain what I found here in case it effects someone else.
The full call history leading to my problem went something like this:
Start Le Scan
Find device I care about
Connect to the device's GATT server (which returns a GATT client, and where I provide a BluetoothGattCallback for all the async communication calls)
Tell the GATT client to discoverServices()
A moment later, the BLE system invokes my callback's onServicesDiscovered()
Now I'm ready to start reading characteristics because the service data is loaded, so this is where I invoke that doRead() method in my original post
Tell the GATT client to readCharacteristic()
Go to sleep until the read is done
---- This is where deadlock occurs, but its supposed to:
A moment later, the BLE system invokes my callbacck's onCharacteristicRead()
Notify all waiting threads
Go back to step 7 and repeat
First Mistake:
Originally my onServicesDiscovered() method looked like this:
public void onServicesDiscovered(final BluetoothGatt gatt, int status) {
doRead();
}
When doRead() executes, it is going to sleep and therefore block execution. This prevents the callback method from finishing and apparently gunks up the entire BLE communicaiton system.
Second Mistake:
Once I realized the above issue, I changed the method to the following:
public void onServicesDiscovered(final BluetoothGatt gatt, int status) {
new Thread(new Runnable() {
#Override
public void run() {
doRead();
}
).start();
}
As far as I can tell, the above version of the method should work. I'm creating a new thread on which to run doRead(), so sleeping in doRead() should not have any impact on the BLE thread. But it does! This change had no impact.
----------- Edit Note --------------
After posting this, I really couldn't rationalize why the above anonymous thread wouldn't work. So I tried it again, and this time it did work. Not sure what went wrong the first time, maybe I forgot to call start() on the thread or something...
--------- End Edit Note ------------
The Solution:
Finally, on a whim, I decided to create a background HandlerThread when my class gets instantiated (instead of spinning up an anonymous Thread in onServicesDiscovered()). The method now looks like this:
public void onServicesDiscovered(final BluetoothGatt gatt, int status) {
mBackgroundHandler.post(new Runnable() {
#Override
public void run() {
doRead();
}
).start();
}
The above version of the method works. The call to doRead() successfully iterates over each characteristic as the previous one is read.
I have solved this problem by adding the following code
#Override
public void onCharacteristicWrite(final BluetoothGatt gatt, final BluetoothGattCharacteristic characteristic, int status) {
super.onCharacteristicWrite(gatt, characteristic, status);
new Thread(new Runnable() {
#Override
public void run() {
gatt.readCharacteristic(characteristic);
}
}).start();
}

Stopping a working thread while querying Facebook

CONTEXT
We have this activity method, called at onCreate starting a Thread :
public void retrieveInfoFromFB(){
new Thread(new Runnable(){
#Override
public void run() {
getMyPersonalInfo();
getMeEvents();
}}).start();
}
getMyPersonalInfo() and getMeEvents() do a Request to Facebook both like that:
if (session!=null && session.isOpened()){
Request request=new Request(session,"/fql",params, HttpMethod.GET,new Request.Callback() {
public void onCompleted(Response response){
// do something with response
}
});
Request.executeAndWait(request);
}
PROBLEM
When the connection is low (not absent, just very low) we have this Thread "working" forever without stopping after a while, yes we already tried to use a RequestBatch with setTimeout(milliseconds) for the Requests, but this seemed not to work.
QUESTION
Is there a way to stop the "retrieveInfoFromFB" thread after (let's say) 10 seconds, while is still waiting for the response from Facebook requests?
p.s
I searched in stackoverflow questions, it seems that all the methods like myThread.destroy() or myThread().interrupt(), are deprecated. And we can't use a while with a flag to do these two request because they must be done just once.
Thank you for your patience.
There is no way to stop the thread communicating with FB (unless you stop the process). However, you can ask the thread to stop itself.
For that you need the FB thread to periodically check if any other process or thread asked it to stop working.
Check out this tutorial on threads: http://docs.oracle.com/javase/tutorial/essential/concurrency/interrupt.html, but basically you want this:
// communicating with FB
try {
Thread.sleep(1000); sleep one second to give other threads a chance
} catch (InterruptedException e) {
// We've been interrupted: stop talking to FB and return
return;
}
or
// do some more FB work
if (Thread.interrupted()) {
// We've been interrupted: no more FB
return;
}
On either case it is the FB thread that must periodically check if it is time to stop, as it is its job to do any cleanup that might be required.

Categories