1

I have two APIs that return two different Results classes. We combine these two results to get a finalClass.

Basically, if these Apis are run at the Same time ,

  1. if it receives Class A first with a certain result (G,H), it doesn't matter what class B is (we will not wait for serviceAPI B), just return Final class from table below.

  2. If Class A does not have a certain result, we have to wait for combine both results (A & B) to get Final class.

I'm trying to use these stackoverflow articles, to process this. I prefer not to mark them with an interface marker class (these are legacy objects), however open to it as second option.

Return the future that gets executed first with a specific condition on the response

In java, how do I process CompletableFutures and get the first desireable result that completes?

public class A {
   public String resultA;
}

public class B {
   public int resultB;
}

public class Final {
   public String resultFinal;
}

CompletableFuture<A> futureA = CompletableFuture.supplyAsync(() -> serviceA.getAPI());
CompletableFuture<B> futureB = CompletableFuture.supplyAsync(() -> serviceB.getAPI());

CompletableFuture.allOf(futureA,futureB).join(); 

enter image description here

open to making both classes a marker interface

public class A implements MarkerResponse  {
public class B implements MarkerResponse  {

public interface MarkerResponse  {}

Marker interface

Currently using Spring Boot with Java 8. Context: the real service dual apis can be variable 1-5 min, so trying to do performance improvement if possible.

mattsmith5
  • 540
  • 4
  • 29
  • 67
  • See https://stackoverflow.com/a/70724649/402428 – michid Jun 16 '23 at 09:15
  • thanks, @michid will check out your answer, and new Holger answer below, appreciate it ! – mattsmith5 Jun 16 '23 at 09:31
  • btw @michid we are doing this for performance speed reasons, if ServiceA finishes first and it has certain criteria, (we will not wait for serviceB to finish) we'll take the results. both services API should be called start at the same time. I will try and test this, appreciate it – mattsmith5 Jun 16 '23 at 15:53

1 Answers1

2

Since you need the result of A in either case, to determine whether you need the result of B, you can simply chain the decision as a dependent operation on A:

CompletableFuture<Final> result = futureA.thenCompose(a ->
    a.resultA.equals("G") || a.resultA.equals("H")?
        CompletableFuture.completedFuture(new Final("success")):
    futureB.thenApply(b -> new Final(b.resultB == 1? "fail": "error")));

Note that when success is likely and the benefit of running A and B in parallel rather low, you may even decide to commence B only when necessary:

CompletableFuture<Final> result = futureA.thenCompose(a ->
    a.resultA.equals("G") || a.resultA.equals("H")?
        CompletableFuture.completedFuture(new Final("success")):
        CompletableFuture.supplyAsync(
            () -> new Final(serviceB.getAPI().resultB == 1? "fail": "error")));
Holger
  • 285,553
  • 42
  • 434
  • 765
  • 1
    Then, the first variant is what you want. It assumes that you start both operations first, like given in the question, creating `futureA` and `futureB`. Then, it will not wait for `futureB` if the criteria is met. – Holger Jun 16 '23 at 16:05
  • thanks, one more question, if we are calling this in a method, and we definitely need the results of ServiceA to process, can we call Service A synchronously (without a future)? and Service B in an asynchronous future, that way we only call 2 threads, vs 3 in the answer above (1 method, plus + 2 futures) ,is that correct in my understanding? can you write a third subset answer? appreciate it! – mattsmith5 Jun 16 '23 at 16:40
  • 1
    If the code is as shown in the question, it should work without problems. Just keep in mind to commence the async operation first, before performing the synchronous one, `CompletableFuture futureB = CompletableFuture.supplyAsync(() -> serviceB.getAPI()); A a = serviceA .getAPI(); Final result = a.resultA.equals("G") || a.resultA.equals("H")? new Final("success"): new Final(futureB.join().resultB == 1? "fail": "error");` – Holger Jun 19 '23 at 07:57