Need some code recommendations. I need to call api which run some proccess on service.
First response show that proccess is begin and need to check each minute is proccess completed calling api. Now I just call Thread.Sleep before each request, this way quick but dirty. how can i improve the code?
// call api, that run some process. it`s long operation which can take up to 15 minutes
boolean isDone = false;
Response<?> proccessRunResponse = execute(request());
// if sucess, operation started successfully
if(proccessRunResponse.isSuccess()) {
// now i need to check status each minute and then retry operation(run proccess req, check status) if the process is complete
while (!isDone) {
waitUntilIsDone()
// request for check status that need to call until response is comleted
Response<?> status = execute(getRequestForCheckStatus());
ResponceWrapper res = (ResponceWrapper) status;
// status can be: in progess, queued etc..
if (res.isComplete()) {
isDone = true;
// exit loop and retry operation
}
}
}
}
private void waitUntilTaskDone() throws InterruptedException {
TimeUnit.SECONDS.sleep(60);
}
In your scenario, you can use java.util.concurrent.CompletableFuture of jdk to finish. The below is pseudocode to show how to do. You should modify it according to your actual code.
import java.util.concurrent.CompletableFuture;
// invoke request() in asynchronous
CompletableFuture<Response> cf = CompletableFuture.supplyAsync(() -> {
return execute(request());
});
// if success:
cf.thenAccept((result) -> {
System.out.println("response" + result);
});
// if fail
cf.exceptionally((e) -> {
e.printStackTrace();
return null;
});
// here should do other things
Related
I am using jersey-client - 2.26 to make an HTTP call.
I am making the async call using the "async()" method.
I loop through my list and make multiple async calls.
Due to this "async" call, it does not wait for the response of the call and go to the next iteration and initiate another call.
Now if the loop executes for 10 times, it will make 10 calls, now initiating this call is correct in loop, but I want to wait for the responses fo the all 10 calls and then want to execute some other code.
private Client getClient() {
SslConfigurator sslConfig = SslConfigurator.newInstance().trustStoreFile(keyStorePath)
.trustStorePassword(keyStorePassword).keyStoreFile(keyStorePath).keyPassword(keyStorePassword);
SSLContext sslContext = sslConfig.createSSLContext();
final Client client = ClientBuilder.newBuilder().sslContext(sslContext)
.hostnameVerifier(new HostnameVerifier() {
#Override
public boolean verify(String hostname, SSLSession session) {
if (hostname.equals("localhost")) {
return true;
} else {
return false;
}
}
}).build();
return client;
}
==================================================================
javax.ws.rs.client.Client client = getClient();
for (BPMInput bpmInputObje : bpmInputList) {
WebTarget wt = client.target(BPM_PROCESS_URL + "?tenantId=" + reqInput.getTenantId());
System.out.println("Async call is started.");
Builder builder = wt.request(MediaType.APPLICATION_JSON);
/* this function will set header parameters in new HTTP call */
setHeaderParametersForAsyncCall(reqInput, builder);
// ******** now call the async call ************
builder.async().post(Entity.json(payload), new InvocationCallback() {
#Override
public void completed(Object obj) {
try {
BPMResponse bpmResponse = mapper.readValue(mapper.writeValueAsString(obj), BPMResponse.class);
System.out.println("Async call after completion forward navigation : "
+ bpmResponse.getNavigation().getForward().toString());
System.out.println("Async call after completion backword navigation : "
+ bpmResponse.getNavigation().getBackward().toString());
} catch (IllegalArgumentException | IOException e) {
e.printStackTrace();
}
}
#Override
public void failed(Throwable arg0) {
System.out.println("Async call is failed : " + arg0);
}
});
}
// Now after this, all calls get initiated, I want to wait for the response
// of these all calls and then want to execute some code.
// ************ code to be executed now is here*************
I want to wait for all the async call to complete and then want to execute some code.
Is it possible with Project Reactor to wait in a mono for an event / condition without needing to use a blocking thread per mono? With a CompletableFuture I can pull such a thing off but I can't see how to do it with Project Reactor.
My problem is that I need to correlate requests with responses. The response time varies wildly and some will even never get a reply and timeout. When on the client side a blocking thread per request isn't a problem but since this is a server application I don't want to end up with spawning a thread per request that blocks waiting for a response.
The API looks something like this:
Mono<Response> doRequest(Mono<Request> request);
Since I don't know how to do it with Reactor I will explain how to do it with a CompletableFuture to clarify what I'm looking for. The API would look like this:
CompletableFuture<Response> doRequest(Request request);
When invoked by a caller a request to a server is made which has a correlation ID in it generated by this method. The caller is returned a CompletableFuture and the method stores a reference to this CompletableFuture in map with the correlation ID as key.
There is also a thread (pool) which receives all the responses for the server. When it receives a response it takes the correlation ID from the response and uses it to look up the original request (ie. the CompletableFuture) in the map and calls complete(response); on it.
In this implementation you don't need a blocking thread per request. This is basically more of a Vert.X / Netty way of thinking? I would like to know how to implement such a thing (if possible) with Project Reactor.
EDIT 25-07-2019:
As per request in the comments to clarify what I'm getting at below is an example of how I would implement this with CompleteableFuture's.
I also noticed I made a mistake which might have been rather confusing: In the CompletableFuture example I passed a Mono as argument. That should have been just a "normal" argument. My apologies and I hope I didn't confuse people too much with it.
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
class NonBlockingCorrelatingExample {
/**
* This example shows how to implement correlating requests with responses without needing a (sleeping)
* thread per request to wait for the response with the use of {#link CompletableFuture}'s.
*
* So the main feat of this example is that there is always a fixed (small) number of threads used even if one
* would fire a thousands requests.
*/
public static void main(String[] args) throws Exception {
RequestResponseService requestResponseService = new RequestResponseService();
Request request = new Request();
request.correlationId = 1;
request.question = "Do you speak Spanish?";
CompletableFuture<Response> responseFuture = requestResponseService.doRequest(request);
responseFuture.whenComplete((response, throwable) -> System.out.println(response.answer));
// The blocking call here is just so the application doesn't exit until the demo is completed.
responseFuture.get();
}
static class RequestResponseService {
/** The key in this map is the correlation ID. */
private final ConcurrentHashMap<Long, CompletableFuture<Response>> responses = new ConcurrentHashMap<>();
CompletableFuture<Response> doRequest(Request request) {
Response response = new Response();
response.correlationId = request.correlationId;
CompletableFuture<Response> reponseFuture = new CompletableFuture<>();
responses.put(response.correlationId, reponseFuture);
doNonBlockingFireAndForgetRequest(request);
return reponseFuture;
}
private void doNonBlockingFireAndForgetRequest(Request request) {
// In my case this is where the request would be published on an MQTT broker (message bus) in a request topic.
// Right now we will just make a call which will simulate a response message coming in after a while.
simulateResponses();
}
private void processResponse(Response response) {
// There would usually be a (small) thread pool which is subscribed to the message bus which receives messages
// in a response topic and calls this method to handle those messages.
CompletableFuture<Response> responseFuture = responses.get(response.correlationId);
responseFuture.complete(response);
}
void simulateResponses() {
// This is just to make the example work. Not part of the example.
new Thread(() -> {
try {
// Simulate a delay.
Thread.sleep(10_000);
Response response = new Response();
response.correlationId = 1;
response.answer = "Si!";
processResponse(response);
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
}
}
static class Request {
long correlationId;
String question;
}
static class Response {
long correlationId;
String answer;
}
}
Yes, it is possible. You can use reactor.core.publisher.Mono#create method to achieve it
For your example:
public static void main(String[] args) throws Exception {
RequestResponseService requestResponseService = new RequestResponseService();
Request request = new Request();
request.correlationId = 1;
request.question = "Do you speak Spanish?";
Mono<Request> requestMono = Mono.just(request)
.doOnNext(rq -> System.out.println(rq.question));
requestResponseService.doRequest(requestMono)
.doOnNext(response -> System.out.println(response.answer))
// The blocking call here is just so the application doesn't exit until the demo is completed.
.block();
}
static class RequestResponseService {
private final ConcurrentHashMap<Long, Consumer<Response>> responses =
new ConcurrentHashMap<>();
Mono<Response> doRequest(Mono<Request> request) {
return request.flatMap(rq -> doNonBlockingFireAndForgetRequest(rq)
.then(Mono.create(sink -> responses.put(rq.correlationId, sink::success))));
}
private Mono<Void> doNonBlockingFireAndForgetRequest(Request request) {
return Mono.fromRunnable(this::simulateResponses);
}
private void processResponse(Response response) {
responses.get(response.correlationId).accept(response);
}
void simulateResponses() {
// This is just to make the example work. Not part of the example.
new Thread(() -> {
try {
// Simulate a delay.
Thread.sleep(10_000);
Response response = new Response();
response.correlationId = 1;
response.answer = "Si!";
processResponse(response);
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
}
}
Im using Java 1.8, dropwizard 1.3.5, and swagger inflection 1.0.13 for my API.
I have a method which takes an HTTP Request, delays 20 seconds, then returns a 200 status code response:
public ResponseContext delayBy20Seconds(RequestContext context) {
ResponseContext response = new ResponseContext().contentType(MediaType.APPLICATION_JSON_TYPE);
Thread.sleep(20000);
response.status(Response.Status.OK);
return response;
}
Say I want to return a 400 status code if the operation (which in this case takes 20 seconds), takes more than 15 seconds. How would I achieve this?
One way to do it without additional libraries is by using the java.util.concurrent package. The surest way to cancel a long-running task like this is by running it in a separate thread.
import java.util.concurrent.*;
...
private ExecutorService exec = Executors.newSingleThreadExecutor();
public ResponseContext delayBy20Seconds(RequestContext context) {
Callable<ResponseContext> task = new Callable<ResponseContext>() {
#Override
public ResponseContext call() throws Exception {
Thread.sleep(20000);
return new ResponseContext().contentType(MediaType.APPLICATION_JSON_TYPE);
}
};
List<Callable<ResponseContext>> tasks = new ArrayList<>();
tasks.add(task);
List<Future<ResponseContext>> done = exec.invokeAll(tasks, 15, TimeUnit.SECONDS);
Future<ResponseContext> task1 = done.get(0);
if (task1.isCancelled()) {
return some Error Response;
}
return task1.get();
}
Your ExecutorService should not be static, because you don't want to share it between threads for this particular use.
The Callable<ResponseContext> implementation is where the work for the long-running task is done. And as it should be obvious in the exec.invokeAll call we tell it how much we're willing to wait. The list of Futures returned will always contain as many elements as the list of tasks, so there's no need to check it for emptiness. We just have to check if the task completed or not.
You could use something like the TimeLimiter from the Google Guava library. This allows you to wrap a callable in an operation that you can call with Timeout. If the callable does not complete the operation in time, it will throw a TimeoutException which you can catch and return a 400 response.
As an example:
TimeLimiter timeLimiter = new SimpleTimeLimiter();
try {
String result = timeLimiter.callWithTimeout(
() -> doSomeHeavyWeightOperation(), 15, TimeUnit.SECONDS);
} catch (TimeoutException e) {
// return 400
}
I am doing a long poll to an API from an android client using retrofit and rxjava. In this case, we wait for a 200 or 408 timeout response from an API and handle the response or reconnect to wait again for more data. This works just fine. I need to stop rx from retrying on certain error codes (like a 500) or if I want to interrupt the process, for example my app was background so let's stop the long poll.
retrofitInterface.startPolling() //returns an Observable
.repeat()
.retry()
.subscribe(new Subscriber<List<Stuff>>() {
#Override
public void onCompleted() {
}
#Override
public void onError(Throwable e) {
}
#Override
public void onNext(List<Stuff> updates) {
//process stuff
}
}
});
I'm not sure if repeatWhen and retryWhen is the right solution here, where I want to keep repeating and retrying http calls to the API but stop repeating in some condition (say I flip a bool in the class to false) or stop retrying if the status code is a 500 instead of say a 408.
It's easier if you wrap your request answer in object of type <Response<?>>, this gives you control over the error code.
What I did for that use case is throwing a specific exception when I have some specific error code:
public <T> T throwExceptionIfFailure(T res) {
Response result = (Response<?>) res;
if (!result.isSuccessful()) {
try {
String msg = result.errorBody().string();
if (result.code() == 401 || result.code() == 403) {
invalidateToken();
msg = context.getString(R.string.invalid_credential);
} else if (result.code() == 502) {
msg = context.getString(R.string.server_down);
}
throw Exceptions.propagate(new IOException(msg));
} catch (Throwable e) {
throw Exceptions.propagate(e);
}
} else {
return res;
}
}
and I added this method in a map function of RX:
serviceRetrofit.getContacts()
.map(result -> serviceRetrofit.throwExceptionIfFailure(result))
.map(result -> createOrUpdateContact(result))
.retry(4)
.onErrorReturn(error -> handleErrorEvent(error))
.doOnCompleted(() -> emitStoreChange(new Store.StoreChangeEvent()))
.subscribe();
I am writing a program that does some batch processing. The batch elements can be processed independently of each other and we want to minimize overall processing time. So, instead of looping through each element in the batch one at a time, I am using an ExecutorService and submitting Callable objects to it:
public void process(Batch batch)
{
ExecutorService execService = Executors.newCachedThreadPool();
CopyOnWriteArrayList<Future<BatchElementStatus>> futures = new CopyOnWriteArrayList<Future<BatchElementStatus>>();
for (BatchElement element : batch.getElement())
{
Future<MtaMigrationStatus> future = execService.submit(new ElementProcessor(batch.getID(),
element));
futures.add(future);
}
boolean done = false;
while (!done)
{
for (Future<BatchElementStatus> future : futures)
{
try
{
if (future.isDone())
{
futures.remove(future);
}
}
catch (Exception e)
{
System.out.println(e.getMessage());
}
if (futures.size() == 0)
{
done = true;
}
}
}
}
We want to be able to allow the batch processing to be cancelled. Because I'm not using a loop, I can't just check at the top each loop if a cancel flag has been set.
We are using a JMS topic to which both the BatchProcessor and ElementProcessor will be listening to inform them the batch has been cancelled.
There are a number of steps in the ElementProcess call() after which some of them the processing can be safely stopped but there's a point of no return. The class has this basic design:
public class ElementProcessor implements Callable, MessageListener
{
private cancelled = false;
public void onMessage(Message msg)
{
// get message object
cancelled = true;
}
public BatchElementStatus call()
{
String status = SUCCESS;
if (!cancelled)
{
doSomehingOne();
}
else
{
doRollback();
status = CANCELLED;
}
if (!cancelled)
{
doSomehingTwo();
}
else
{
doRollback();
status = CANCELLED;
}
if (!cancelled)
{
doSomehingThree();
}
else
{
doRollback();
status = CANCELLED;
}
if (!cancelled)
{
doSomehingFour();
}
else
{
doRollback();
status = CANCELLED;
}
// After this point, we cannot cancel or pause the processing
doSomehingFive();
doSomehingSix();
return new BatchElementStatus("SUCCESS");
}
}
I'm wondering if there's a better way to check if the batch/element has been cancelled other than wrapping method calls/blocks of code in the call method in the if(!cancelled) statements.
Any suggestions?
I don't think you can do much better than what you are currently doing, but here is an alternative:
public BatchElementStatus call() {
return callMethod(1);
}
private callMethod(int methodCounter) {
if (cancelled) {
doRollback();
return new BatchElementStatus("FAIL");
}
switch (methodCounter) {
case 1 : doSomethingOne(); break;
case 2 : doSomethingTwo(); break;
...
case 5 : doSomethingFive();
doSomethingSix();
return new BatchElementStatus("SUCCESS");
}
return callMethod(methodCounter + 1);
}
Also, you want to make cancelled volatile, since onMessage will be called from another thread. But you probably don't want to use onMessage and cancelled anyway (see below).
Other minor points: 1) CopyOnWriteArrayList<Future<BatchElementStatus>> futures should just be an ArrayList. Using a concurrent collection mislead us into thinking that futures is on many thread. 2) while (!done) should be replaced by while (!futures.isEmpty()) and done removed. 3) You probably should just call future.cancel(true) instead of "messaging" cancellation. You would then have to check if (Thread.interrupted()) instead of if (cancelled). If you want to kill all futures then just call execService.shutdownNow(); your tasks have to handle interrupts for this to work.
EDIT:
instead of your while(!done) { for (... futures) { ... }}, you should use an ExecutorCompletionService. It does what you are trying to do and it probably does it a lot better. There is a complete example in the API.
Future has a cancel(boolean) method that will interrupt the running thread if true is passed in
so replace the if(!cancelled) checks with if(Thread.interrupted()) and return when you got a interrupt (you're not currently)
note that this will reset the interrupted flag to false (so if(Thread.interrupted()&&Thread.interrupted()) will be false) if you don't want to reset it use Thread.currentThread().isInterrupted() this maintains the flag for subsequent checks
or you can reset the flag to interrupted with Thread.currentThread().interrupt();
besides that use this inside the waiting while
for(Iterator<Future<MtaMigrationStatus>> it = futures.iterator();it.hasNext();){
Future<MtaMigrationStatus> future = it.next();
try
{
if (future.isDone())
{
it.remove();//<<--this avoids concurrent modification exception in the loop
}
}
catch (Exception e)
{
System.out.println(e.getMessage());
}
}
if (futures.size() == 0)//outside the inner for loop and inside the while (or make the condition this) for micro-optimizing this check
{
done = true;
}
Your ElementProcessor can extend from java.util.concurrent.FutureTask which is
A cancellable asynchronous computation. This class provides a base
implementation of Future, with methods to start and cancel a
computation, query to see if the computation is complete, and retrieve
the result of the computation.
The FutureTask class is an implementation of Future that implements
Runnable, and so may be executed by an Executor.
FutureTask has a cancel method which you can implement to do some cancel specific operations. Also, if FutureTask is canceled it will not be executed anymore, so you don't have to check always the status.