I have a plugin method that acts on remote hardware via Bluetooth.
It sends a command to the hardware, which executes some action.
After the hardware action finishes a callback defined outside of my method is called.
I only want to call CallbackContext.success(...) or CallbackContext.error(...) after the callback is called, so i want to wait for my callback to be called.
How would i go about this?
E.g. part of CordovaPlugin-class:
public void actOnHardware(CallbackContext callbackContext)
{
this.verifiyBluetoothEnabled();
this.hardwareConnection.doSomething()
// Now wait for the callback to complete before calling
// callbackContext.success() or error()
callbackContext.error("Not implemented.");
}
#Override
public void hardwareActionCallback(result)
{
// Notify actOnHardware() that we're finished.
}
This seems to be more of a Java thing, but i can't get my head to wrap around it.
Is using Object.wait() and Object.notify() a viable option or does calling wait() prevent the callback from getting called due to thread stuff? If so - how to solve this?
E.g. is it sufficient to just do:
private Object lockObj;
private boolean actionFinished;
public void actOnHardware(CallbackContext callbackContext)
{
this.verifiyBluetoothEnabled();
this.actionFinished = false;
this.hardwareConnection.doSomething()
while(!this.actionFinished)
this.lockObj.wait();
callbackContext.error("Not implemented.");
}
#Override
public void hardwareActionCallback(result)
{
this.actionFinished = true;
this.lockObj.notify();
}
Kind Regards
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 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);
}
});
The problem is, that I stop Dropwizard application (via ctrl + c) and I have inserted a Shutdown Hook in main class to do some stuff before shutdown. But now ServerConnector for the application is closed before I can do what I want to do.
There is a polling service (polls one of my resources) and I need to tell them, that application will go down soon to prevent some problems. I need at least 15 seconds before ressource goes down.
Some idea how to solve this problem?
You can use a lifecycle hook to manage certain resources.
public class ManagedObject implements Managed {
private final Object obj;
public ManagedObject(Object obj) {
this.obj = obj;
}
#Override
public void start() throws Exception {
// Do something to start the object
}
#Override
public void stop() throws Exception {
// Do something to stop the object
}
}
Then register on the environment
ManagedObject myManagedObject = new ManagedObject(obj);
environment.lifecycle().manage(myManagedObject);
Add a Dropwizard Task that will change the state of a static field (or however you want to pass the data) which your polling resource will be using to respond.
public class ShutdownTask extends Task {
private int timeoutSeconds;
public ShutdownTask (int timeoutSeconds) {
super("shutdown");
this.timeoutSeconds = timeoutSeconds;
}
#Override
public void execute(ImmutableMultimap<String, String> parameters, PrintWriter output) throws Exception {
// you probably can take the timeout parameter from the request via 'parameters' instead of the constructor.
PollingResource.shuttingDownIn = timeoutSeconds;
}
}
environment.admin().addTask(new ShutdownTask(15));
Then write a bash script which will curl to task
curl -X POST http://dw.example.com:8081/tasks/shutdown
And:
This is probably not recommended (people don't like System.exit(0)) but you can add the following to execute method:
Thread.sleep(timeoutSeconds * 1000);
System.exit(0)
Or do the waiting and kill the dropwizard app in the bash script.
kill -SIGINT <pid>
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.