I have a small Spring Boot app waiting for REST calls to start an async job. However what I'd like to do next is get results of those async jobs and store them in DB. But I don't know how to use object returned with Future asynchronically.
Here is more or less what I have:
#RequestMapping("/vlan/{id}/{name}")
public void performVLANConfig(#PathVariable("id") int id, #PathVariable("name") String name) {
logger.debug("Received req");
Future<ProcessedRequest> processedRequestFuture= asyncService.processVlan(id, name);
processedRequestRepository.save(processedRequest);
}
But now it just waits for async call to end. Is there any way to let the async method live its life and after it has completed store this completition error?
You need to attach a callback. If you using Future then you can't attach a callback to it, assign to a ListenableFuture instead, the service needs to return a ListenableFuture of course.
ListenableFuture<ProcessedRequest> future = asyncService.processVlan(id, name);
future.addCallback(new ListenableFutureCallback<ProcessedRequest>() {
#Override
public void onFailure(Throwable throwable) {
// deal with it
}
#Override
public void onSuccess(ProcessedRequest processedRequest) {
processedRequestRepository.save(processedRequest);
}
});
Related
I have a Controller that must accept a request and do not wait for the finishing of the processing, give a response.
#PostMapping
#ResponseStatus(HttpStatus.CREATED)
public void processEvent(#RequestBody RequestMyObjectDTO requestMyObjectDTO) {
MyProcessor.process(requestMyObjectDTO);
}
After I give a response, I must execute the processing.
#Async
public void process(RequestMyObjectDTO myRequestObject) {
List<TestObject> testObjects= repository.findAllTestObject();
if (testObjects.isEmpty()) {
return;
}
.............
Is there any difference in where I will go to the database, in the asynchronous method, or outside it? In my case in Controller for example.
How it will impact behavior and what approaches are better?
Given that I need a check:
List<TestObject> testObjects= repository.findAllTestObject();
if (testObjects.isEmpty()) {
return;
}
At the same time, I expect that the controller may receive millions of requests.
I have an HTTP request that triggers a long-running task (multiple HTTP requests to another service) that is supposed to be completed in the background while the original requests complete.
So what I do is
public void triggerWork(#RequestBody SomeObject somObject) {
return new ResponseEntity<>(startWorkAndReturn(somObject), HttpStatus.OK);
}
public void startWorkAndReturn(SomeObject someObject) {
Observable.create(observableEmitter -> {
// do the work with someObject here and at some time call
observableEmitter.onNext("result");
}).subscribe(new Observer<Object>() {
#Override
public void onSubscribe(Disposable disposable) {
}
#Override
public void onNext(Object o) {
// called at some unknown time
}
#Override
public void onError(Throwable throwable) {
}
#Override
public void onComplete() {
// currently not used as all the work is done in onNext but maybe that's a mistake
}
});
return;
}
But this seems to block the request until all the work has been done. Which already seems odd to me, since I never call onComplete, which in itself might be a mistake. But still, I am wondering how to create a request that immediately returns after triggering a background worker.
Is Flowables the solution here? I am going to refactor to those anyways to handle backpressure. Or do I need to create a background worker Thread? What is the best practice here?
Thanks
I would use Observable.fromCallable{} since you need emit only single event. That will handle onCompleate call. From information you share I don`t know how can you properly handle disposable. You should add subscribeOn() and observeOn() operators that will define on which thread 'work' should be processed and result should be observed.
Docs ref:
http://reactivex.io/RxJava/javadoc/io/reactivex/Observable.html#fromCallable-java.util.concurrent.Callable-
http://reactivex.io/documentation/operators/subscribeon.html
http://reactivex.io/documentation/operators/observeon.html
I know there are probably a couple ways to do this, just looking for the most efficient and concise way to go about it:
public Object giveMeNewObject() {
final Object result = null;
SomeApiClient.start(new Callback() { // starts an async process
#Override
public void onSuccess(Object somethingNew) {
result = somethingNew; //ERROR; can't set cause final
}
});
return result; //result is null, cause Async already finished
}
From your code - this is modified on fly so correct mistakes and all will work as you expect - caller will wait untill 3rd party finishes the processing and will get the result of that process:
public Object giveMeNewObject() {
CountDownLatch latch=new CountDownLatch(1);
Callback callback=new Callback() {
public sometype result=null;
#Override
public void onSuccess(Object somethingNew) {
result = somethingNew; //ERROR; can't set cause final
latch.countDown();
}
});
SomeApiClient.start(callback);
latch.await(sometimetowait);
return callback.result;
}
Read the documentation of AsyncTask. Your job should be done in doInBackground method and the result should be returned by that method. Later on you can use get(Timeout) method to retrieve that returned value. get will even block if the computation in doInBackground is not complete yet for given ammount of the time.
You can find tons of examples of how to use async task. One of them is in the API documentation (link above)
I'm using Square's Retrofit Client to make short-lived json requests from an Android App. Is there a way to cancel a request? If so, how?
For canceling async Retrofit request, you can achieve it by shutting down the ExecutorService that performs the async request.
For example I had this code to build the RestAdapter:
Builder restAdapter = new RestAdapter.Builder();
restAdapter.setEndpoint(BASE_URL);
restAdapter.setClient(okClient);
restAdapter.setErrorHandler(mErrorHandler);
mExecutorService = Executors.newCachedThreadPool();
restAdapter.setExecutors(mExecutor, new MainThreadExecutor());
restAdapter.setConverter(new GsonConverter(gb.create()));
and had this method for forcefully abandoning the requests:
public void stopAll(){
List<Runnable> pendingAndOngoing = mExecutorService.shutdownNow();
// probably await for termination.
}
Alternatively you could make use of ExecutorCompletionService and either poll(timeout, TimeUnit.MILISECONDS) or take() all ongoing tasks. This will prevent thread pool not being shut down, as it would do with shutdownNow() and so you could reuse your ExecutorService
Hope it would be of help for someone.
Edit: As of OkHttp 2 RC1 changelog performing a .cancel(Object tag) is possible. We should expect the same feature in upcoming Retrofit:
You can use actual Request object to cancel it
okClient.cancel(request);
or if you have supplied tag to Request.Builder you have to use
okClient.cancel(request.tag());
All ongoing, executed or pending requests are queued inside Dispatcher, okClient.getDispatcher(). You can call cancel method on this object too. Cancel method will notify OkHttp Engine to kill the connection to the host, if already established.
Edit 2: Retrofit 2 has fully featured canceling requests.
Wrap the callback in a delegate object that implements Callback as
well. Call some method to clear out the delegate and have it just
no-op whenever it gets a response.
Look at the following discussion
https://plus.google.com/107765816683139331166/posts/CBUQgzWzQjS
Better strategy would be canceling the callback execution
https://stackoverflow.com/a/23271559/1446469
I've implemented cancelable callback class based on answer https://stackoverflow.com/a/23271559/5227676
public abstract class CancelableCallback<T> implements Callback<T> {
private static List<CancelableCallback> mList = new ArrayList<>();
private boolean isCanceled = false;
private Object mTag = null;
public static void cancelAll() {
Iterator<CancelableCallback> iterator = mList.iterator();
while (iterator.hasNext()){
iterator.next().isCanceled = true;
iterator.remove();
}
}
public static void cancel(Object tag) {
if (tag != null) {
Iterator<CancelableCallback> iterator = mList.iterator();
CancelableCallback item;
while (iterator.hasNext()) {
item = iterator.next();
if (tag.equals(item.mTag)) {
item.isCanceled = true;
iterator.remove();
}
}
}
}
public CancelableCallback() {
mList.add(this);
}
public CancelableCallback(Object tag) {
mTag = tag;
mList.add(this);
}
public void cancel() {
isCanceled = true;
mList.remove(this);
}
#Override
public final void success(T t, Response response) {
if (!isCanceled)
onSuccess(t, response);
mList.remove(this);
}
#Override
public final void failure(RetrofitError error) {
if (!isCanceled)
onFailure(error);
mList.remove(this);
}
public abstract void onSuccess(T t, Response response);
public abstract void onFailure(RetrofitError error);
}
Usage example
rest.request(..., new CancelableCallback<MyResponse>(TAG) {
#Override
public void onSuccess(MyResponse myResponse, Response response) {
...
}
#Override
public void onFailure(RetrofitError error) {
...
}
});
// if u need to cancel all
CancelableCallback.cancelAll();
// or cancel by tag
CancelableCallback.cancel(TAG);
This is for retrofit 2.0, the method call.cancel() is there which cancels the in-flight call as well. below is the document definition for it.
retrofit2.Call
public abstract void cancel()
Cancel this call. An attempt will be made to cancel in-flight calls, and if the call has not yet been executed it never will be.
Now there is an easy way in latest version of Retrofit V 2.0.0.beta2. Can implement retry too.
Take a look here How to cancel ongoing request in retrofit when retrofit.client.UrlConnectionClient is used as client?
According to the Retrofit 2.0 beta 3 changelog via link https://github.com/square/retrofit/releases/tag/parent-2.0.0-beta3
New: isCanceled() method returns whether a Call has been canceled. Use this in onFailure to determine whether the callback was invoked from cancelation or actual transport failure.
This should make stuff easier.
I might be a bit late, but I've possibly found a solution.
I haven't been able to prevent a request from being executed, but if you're satisfied with the request being performed and not doing anything, you might check this question and answer, both made by me.
Does anyone know how to monitor long-running server-side processes in GWT, other than polling the server? We need to do some time-consuming, multiple-step, I/O-bound processing on the server, and it would be nice to display the progress of this processing in the browser.
This is fairly easy to handle in GWT.
The long-running process is either triggered by a GWT RPC call, in which case you have your entry point, or it isn't, in which case you need to start this off manually.
Remember that GWT RPC calls are asynchronous so they don't need to return immediately. You need an RPC call like checkStatus(). So you can do things like:
public class JobStatus {
private boolean done;
// other info
// ...
}
public class JobStatusCallback<JobStatus> extends AsyncCallback {
public final void onSuccess(JobStatus result) {
if (result.isDone()) {
done();
} else {
checkAgain();
}
}
public final void onFailure(Throwable caught) {
error(caught);
checkAgain();
}
public void done() { // override
}
public void checkAgain() {
service.checkStatus(this);
}
public void error(Thorwable t) { // override
}
});
and in your RPC service:
void checkStatus(AsyncCallback<JobStatus> callback);
Your server can take as long as it likes (within reason) to return from checkStatus(). It can return because the job is done or just with a job status update. The above will continue looping until the job status done flag is set.
I think it depends on your process but if you are going to do something like Data Streaming you can use Server Push (Or Comet) technic.GWT supports Comet implementation.
google GWT+Comet ,or GWT+COMET+Tomcat,i read about comet and gwt in "Google Web Toolkit Applications" Book(gwtapps.com).