Re: Counter-intuitive behavior of CompleteableFuture
Alex Otenko via Concurrency-interest <[email protected]> Thu, 20 May 2021 21:03:57 +0100
| Newsgroups | gmane.comp.java.jsr.166-concurrency |
|---|---|
| Message-ID | <CANkgWKi70v_UdRdKoR18+=y5Lr_xmk5x3ZD+TT-MBtB_m01FVg@mail.gmail.com> |
It is a little more nuanced than that. You may not know that the CF is being completed on your behalf. Enter orTimeout... Furthermore, try to devise a chain of CFs that borrow a pooled resource, then finally return it back to the pool. Now if this construct is wrapped in orTimeout, you can see the resource borrowed, but downstream stages don't release it, because they will be bypassed by exceptional completion by orTimeout. Alex On Thu, 20 May 2021, 13:59 Viktor Klang via Concurrency-interest, < [email protected]> wrote: > A solution which has been used very successfully in Scala is the > distinction between Promise (write a single value 0..1 times) and Future > (read a single value 0..N times), which means that only the thread who owns > a reference to the Promise can write values, which means that Futures can > be freely shared since consumers cannot manipulate the result "further up > the chain". > > You can achieve something similar in Java by separating CompletableFuture > from CompletionStage. > > public static void main(String[] args) { > CompletableFuture<String> initial = new CompletableFuture<>(); > > CompletionStage<String> withSteps = initial > .thenApply(s -> { > System.out.println("STEP1: " + s); > return s; > }) > .thenApply(s -> { > System.out.println("STEP2: " + s); > return s; > }); > > CompletionStage<String> timeout = withSteps; > > timeout.whenComplete((s, throwable) -> > System.out.println("TIMEOUT: " + throwable)); > > timeout.completeExceptionally(new RuntimeException("TIMEOUT")); <--- > now won't compile > initial.complete("SUCCESS"); > } > > > On Thu, May 20, 2021 at 12:50 PM Michał Górniewski via > Concurrency-interest <[email protected]> wrote: > >> What bothers me here is API of CompletableFuture itself, e.g: >> >> public CompletableFuture<ProcessingOutput> >> executeProcessing(Function<Path, ProcessingOutput> processor) { >> Path data = prepareData(); >> return CompletableFuture.supplyAsync(() -> processor.apply(data), >> processingExecutor) >> .whenComplete((o, ex) -> cleanup(data)); >> } >> >> Callers of this method may just break cleanup, without even knowing >> about this, but simply calling complete() on returned CF. But it seems >> that nothing can be done about it. >> >> czw., 20 maj 2021 o 14:40 Benjamin Manes <[email protected]> >> napisał(a): >> > >> > The timeout is applied to the STEP2 future which completes it >> exceptionally. This causes it to not run the mapping function for a result, >> as it was completed prior to that being triggered. You can use copy() to >> decouple the source from the timeout if you want both to complete; e.g. >> cache a long running value but fail a consumer if taking to long. >> > >> > On Thu, May 20, 2021 at 5:31 AM Michał Górniewski via >> Concurrency-interest <[email protected]> wrote: >> >> >> >> With following code: >> >> >> >> ------------------------------ >> >> public static void main(String[] args) { >> >> CompletableFuture<String> initial = new CompletableFuture<>(); >> >> >> >> CompletableFuture<String> withSteps = initial >> >> .thenApply(s -> { >> >> System.out.println("STEP1: " + s); >> >> return s; >> >> }) >> >> .thenApply(s -> { >> >> System.out.println("STEP2: " + s); >> >> return s; >> >> }); >> >> >> >> CompletableFuture<String> timeout = withSteps; >> >> >> >> timeout.whenComplete((s, throwable) -> >> >> System.out.println("TIMEOUT: " + throwable)); >> >> >> >> timeout.completeExceptionally(new RuntimeException("TIMEOUT")); >> >> initial.complete("SUCCESS"); >> >> } >> >> ------------------------------ >> >> >> >> I got output like this: >> >> >> >> ------------------------------ >> >> TIMEOUT: java.lang.RuntimeException: TIMEOUT >> >> STEP1: SUCCESS >> >> ------------------------------ >> >> >> >> I don't understand why "STEP2" is not executed in this case. Is this >> expected? >> >> For me this API is confusing and may create issues like this: >> >> https://github.com/resilience4j/resilience4j/issues/1427 >> >> >> >> Thanks, >> >> Michał Górniewski >> >> _______________________________________________ >> >> Concurrency-interest mailing list >> >> [email protected] >> >> http://cs.oswego.edu/mailman/listinfo/concurrency-interest >> _______________________________________________ >> Concurrency-interest mailing list >> [email protected] >> http://cs.oswego.edu/mailman/listinfo/concurrency-interest >> > > > -- > Cheers, > √ > _______________________________________________ > Concurrency-interest mailing list > [email protected] > http://cs.oswego.edu/mailman/listinfo/concurrency-interest > _______________________________________________ Concurrency-interest mailing list [email protected] http://cs.oswego.edu/mailman/listinfo/concurrency-interest