Advice for an asynchronous programming problem in Java - java

I have a set of classes which encapsulate a unit of work on Google Sheets. After the class's execute method is called, they pass a request to a service, bundled with a callback which the service should call on task completion. (As the tasks are non-critical and repeated frequently, the service just logs errors and does not call the class back if its request fails).
Stripped down, the tasks look like this:
public void execute() {
//preparatory stuff, then...
Request r = new Request(this::callback);
service.execute(r);
}
public void callback(Result result) {
...
}
The call to the service is synchronous but within the service, the Request is queued, executed asynchronously, and the callback is invoked on a new thread. Some of the tasks involve several service invocations, the callback methods may themselves create a Request with a second callback method and invoke the service again. I want that to be invisible to client code.
My problem now is that I would like to run the tasks asynchronously from client code and then execute an arbitrary handler after they are done. One way to do this would be to give the class a callback in the execute() method for it to call once execution is complete. But I'd really rather be able to do this inline in code, this sort of thing:
CompletableFuture.supplyAsync(() -> (new Task()).execute()).whenComplete((result, error) -> {});
The problem with that is, the completion of the execute() method does not signal the end of the task, as the task is still awaiting its callback. The other thing is, that callback might never arrive. I can't figure out how I should go about calling the task such that I can run it asynchronously and inline like in the code above and the whenComplete() will be invoked when the Task class explicitly decides it is finished. I'd also need a timeout, as the tasks's callback may not be invoked.
Any ideas? Note that I control the service invoked by the tasks, so I can change how that works if necessary, but I'd probably rather not.

I'd spend some time looking around in java.util.concurrent. Can't you just use an ExecutorService for a lot of this? You can submit() Callable code and get a future back, you can submit a list of Callables and give a timeout, you can call shutdown() and then awaitTermination() to wait for the processing to stop. You can get these notification callbacks by just submitting a Callable that constructs with the callback interface and invokes it when it feelsl like it's done.
Failing this, you might look at actors. Your concurrency pattern would likely be very easy in the actor model.

Going to answer my own question here: I just altered the task execute methods to return a CompletableFuture<TaskResult> with TaskResult containing the desired information. The task stores the CompletableFuture internally and calls complete() as needed in later callbacks. Not sure why I had trouble seeing this solution.

Related

How can we monitor the exact idle time between submitting a task as CompletableFuture for execution and actually running it?

I'm trying to gather specific data on how long a task waits between being submitted and actually being executed. The idea is to be able to closely monitor the existing threadpool and tasks that are submitted for execution.
Let's assume I have an ExecutorService with a fixedThreadPool.
I'm also using a composition of completableFutures to perform a set of tasks asynchronously.
I'd like to be able to track within my logs the exact time a certain task had to wait in the queue before being taken for execution.
The way I see it I need two things:
A way to label CompletableFuture (or the Supplier functions passed to CompletableFuture.supplyAsync())
This I could potentially do by providing a wrapper method for the Supplier as mentioned here https://stackoverflow.com/a/57888886 and overwrite the CompletableFuture.supplyAsync() method so it will internally log which named supplier was provided
A way to monitor the time between the submission and execution of a specific Runnable to the threadpool executor.
This I can achieve by extending the ThreadPoolExecutorand providing some custom logging in the beforeExecute() and execute() method
What I'm kind of 'stuck' on now is linking both of them together. The beforeExecute() method override gives me the thread and the runnable - but the thread in itself doesn't tell me much yet, and the runnable isn't named in any way so I can't really know which exact task is taken for execution. Of course I can add additional logs in the task implementations themselves and then assume that they will be right next to the log from beforeExecute(). The problem still remains for execute() itself, since that one is called internally after using the CompletableFuture composition.
So how can I properly link the information from the executor service, with some labelling of the exact tasks provided as CompletableFutures as in the example below?
List<Foo> results = createResults();
results.forEach(r -> CompletableFuture.completedFuture(r)
.thenCompose(result -> addSomething(result, something)
.thenCombine(addSomethingElse(result, somethingElse), (r1, r2) -> result)
.thenCompose(r -> doSomething(result).thenCompose(this::setSomething))
.thenApply(v -> result))));
...
// At some point join() is called to actually wait for execution and completion
listOfFutures.join()
And each of the functions called within return a CompletableFuture<Foo> created by:
private CompletableFuture<Foo> setSomething(Foo foo) {
return CompletableFuture.supplyAsync(() -> {
foo.description = "Setting something";
return foo;
}, myExecutorService);
}
So even by wrapping the Supplier<T> to have it labeled, how am I able to link this with the tracking within the execute() and beforeExecute() method of the ThreadPoolExecutor when that one operates on Runnables instead of Suppliers?

Java - series of async calls, but have to wait for a response of each async call before proceeding

The existing flow for single async call is as follows:
Make a call to an internal java service that sends the message based call.
At this point, that process is done.
An observer pattern has been implemented to be called when a response (message based) comes back to the java service.
The onResponse method is called and completion of the response should happen.
Edited to give more specifics:
I have tested with CountDownLatch and Phaser to get both of these scenarios working where my main thread is responsible for spawning off the parallel thread async call. The parallel thread completes, and the main thread waits to be notified that the response from the async call has been received. If the response signifies a success, move on to the next parallel call, and so on. Here is an example of Phaser that worked well. Question is, am I on the right path, or is there something easier/better?
main thread:
new Phaser(1);
for (iteration of number of request objects received){
create new thread, call serviceMethod.
phaser.arriveAndAwaitAdvance; //waits for arrival of registered party
if phaser.isTerminated
stop processing this request;
}
serviceMethod(){
phaser.register
perform call
}
onResponse(){
if SUCCESS
phaser.arriveAndDeregister(); //main thread should continue on to
next call
else
phaser.forceTermination
}
My comments on your question notwithstanding, I'll offer an answer, because I believe I can give you a different sort of answer without seeing any of your code:
By definition an asynchronous call is one where the caller does not block waiting for a response. So if you have a requirement to wait for a response, then you can avoid the problem you are describing by making a series of synchronous calls instead.
Again, paraphrasing a line from your question just a bit: "The process should be that I make the call, but wait for the response before triggering the next call." describes a synchronous calling scenario. In that sense, I suspect you are approaching the problem from the wrong direction.

Which executor is used when composing Java CompletableFutures?

I have a method on some repository class that returns a CompletableFuture. The code that completes these futures uses a third party library which blocks. I intend to have a separate bounded Executor which this repository class will use to make these blocking calls.
Here is an example:
public class PersonRepository {
private Executor executor = ...
public CompletableFuture<Void> create(Person person) {...}
public CompletableFuture<Boolean> delete(Person person) {...}
}
The rest of my application will compose these futures and do some other things with the results. When these other functions that are supplied to thenAccept, thenCompose, whenComplete, etc, I don't want them to run on the Executor for the repository.
Another example:
public CompletableFuture<?> replacePerson(Person person) {
final PersonRepository repo = getPersonRepository();
return repo.delete(person)
.thenAccept(existed -> {
if (existed) System.out.println("Person deleted"));
else System.out.println("Person did not exist"));
})
.thenCompose(unused -> {
System.out.println("Creating person");
return repo.create(person);
})
.whenComplete((unused, ex) -> {
if (ex != null) System.out.println("Creating person");
repo.close();
});
}
The JavaDoc states:
Actions supplied for dependent completions of non-async methods may be performed by the thread that completes the current CompletableFuture, or by any other caller of a completion method.
Side question: Why is there an or here? In what case is there another caller of a completion method that does not complete the current future?
Main question: If I want all the println to be executed by a different Executor than the one used by the repository, which methods do I need to make async and provide the executor manually?
Obviously the thenAccept needs to be changed to thenAcceptAsync but I'm not sure about that point onwards.
Alternative question: Which thread completes the returned future from thenCompose?
My guess is that it will be whatever thread completes the future returned from the function argument. In other words I would need to also change whenComplete to whenCompleteAsync.
Perhaps I am over complicating things but this feels like it could get quite tricky. I need to pay a lot of attention to where all these futures come from. Also from a design point of view, if I return a future, how do I prevent callers from using my executor? It feels like it breaks encapsulation. I know that all the transformation functions in Scala take an implicit ExecutionContext which seems to solve all these problems.
Side Question: If you assigned the intermediate CompletionStage to a variable and call a method on it, it would get executed on the same thread.
Main Question: Only the first one, so change thenAccept to thenAcceptAsync -- all the following ones will execute their steps on the thread that is used for the accept.
Alternative Question: the thread that completed the future from thenCompose is the same one as was used for the compose.
You should think of the CompletionStages as steps, that are executed in rapid succession on the same thread (by just applying the functions in order), unless you specifically want the step to be executed on a different thread, using async. All next steps are done on that new thread then.
In your current setup the steps would be executed like this:
Thread-1: delete, accept, compose, complete
With the first accept async, it becomes:
Thread-1: delete
Thread-2: accept, compose, complete
As for your last question, about the same thread being used by your callers if they add additional steps -- I don't think there is much you can do about aside from not returning a CompletableFuture, but a normal Future.
Just from my empirical observations while playing around with it, the thread that executes these non-async methods will depend on which happens first, thenCompose itself or the task behind the Future.
If thenCompose completes first (which, in your case, is almost certain), then the method will run on the same thread that is executing the Future task.
If the task behind your Future completes first, then the method will run immediately on the calling thread (i.e. no executor at all).

Android/Java sequence of serially executed tasks

How can I have a sequence of tasks that run one after another (Serially). I'm not using AsyncTasks, but the loopj AsyncHttpClient, but the question applies to other tasks as well.
The way it's structured is: Application has main method that performs multiple async calls. These calls are mutually serial, one must be run after another.
Main() calls FuncA() which fires an async request. Control is returned to Main()
The request handler calls OnFuncAComplete(), which triggers Main() to proceed:
Main() calls FuncB() which fires an async request. Control is returned to Main()
The request handler calls OnFuncBComplete(), which triggers Main() to proceed:
rinse, repeat
How can I write main to perform all these functions in lock-step, how can I pause Main() and in OnFuncXComplete "trigger" main back into action? My first thought was with ReentrantLock's, but I can't seem to get it to work.
Edit: I know I could just call FuncB() from OnFuncAComplete(), but then I'm getting down into callback hell and I want to avoid if possible.
It looks like there may be more than one solution for this. One possibility is to use SynchronousQueue for transferring tasks between your Main and a processor. AsyncTask probably will not be needed, instead your tasks can extend runnables and no need to make callbacks to "unlock" Main()
Create a processing thread that runs a loop and polls SynchronousQueue instance (possibly with timeout). Each element obtained from the queue is a Runnable that the processor thread just executes.
In your Main() you call FuncA(SynchronousQueue q, <...>), FuncB(SynchronousQueue q, <...>), etc. sequentially
Each of FuncX() inserts its runnable task into the queue (q)
Make sure that you can nicely finish your thread once there is no more tasks to run
Have a look at IntentService. It is a Worker service that has only one bg thread an requests are enqueued and processed in a FCFS manner. Responses from service to your Main can be delivered via a BroadcastReceiver that your Main should have registered beforehand.

Telling the asynchronous job to wait in Java

I have a situation where sometimes (not always) my asynchronous job is not able to process results by the time needed and I have to return some kind of message to the client saying that his request is still being prepared by checking for it in the database.
The request and creating necessary object for it is handled in one database Transaction, the asynchronous process is handled in the different Transaction. I am using ScheduledThreadPoolExecutor by passing the runnable instance to the execute method.
The problems that sometimes the client makes a request and while the his browser is loading my asynchronous job is able to prepare the necessary data for it, but sometimes it isn't.
So my question is: Is there anyway I can tell asynchronous job to wait until the data is ready?
I am afraid that using just a Runnable instance you are not be able to tell the process to wait unless you sleep the Thread for sometime or looping and keep asking for the results which both are bad ideas.
In order to make this happen correctly, you should use a FutureTask for this by passing Callable instance to it's constructor. By overriding your call() method you should tell you transactional handler to do the job.
You also need to have some kind of a task manager which will add the task to the queue and creates a thread pool which takes and processes those tasks. For the queue purpose I would suggest to use for e.g.: LinkedBlockingDeque which accepts the generic type of FutureTask.
Also you should have a map of future tasks mapped by their name or something which takes the FutureTask as a value. In terms of waiting for the results when your Thread is processed the given FutureTask already you have to immediately remove it from the futures map. Then when your client requests you should check: if the futures map contains the task get the FutureTask from it and call futureTask.get() on it. This will wait until the task is finished.
This is just approach with which I would go. Hope this helps.

Categories

Resources