Andrey, As you might know Java has it is own Reactive abstractions since 9 [1]. Moreover, an original Reactive Streams library has a bridge with Java [2].
Personally I do not love CompletableFuture because it's API seems questionable to me in various aspects, e.g. mentioned cancellation. Currently I think that the cleanest way is custom abstractions (possibly implementing CompletionStage) at first. And providing bridges to other APIs (including CompletableFuture) as a next step. Various API integrations can come in form of extensions. > JDK classes are well-known and reactive frameworks usually have converters to/from CompletableFuture [1] [2]. Here I have doubts that it is feasible to achieve it fairly. E.g. once again cancellation. While reactive API supports cancellation it will not be possible to cancel computation for anything built from CompletableFuture. [1] https://docs.oracle.com/en/java/javase/14/docs/api/java.base/java/util/concurrent/Flow.Publisher.html [2] https://www.reactive-streams.org/reactive-streams-1.0.3-javadoc/org/reactivestreams/FlowAdapters.html 2021-04-02 12:00 GMT+03:00, Andrey Mashenkov <andrey.mashen...@gmail.com>: > Ivan, > thanks for the link. I think, now I've got what you mean. > > I don't think we want to have any framework as a dependency and rely on > their lifecycle, roadmaps goals and > bother about compatibility. > JDK classes are well-known and reactive frameworks usually have converters > to/from CompletableFuture [1] [2]. > So, users are free to choose any reactive framework. > > I think will need reactive abstractions in near future for Queries API and > maybe Transaction API design. > These projects are good enough where we can get inspiration. > > [1] > https://projectreactor.io/docs/core/release/api/reactor/core/publisher/Mono.html#fromFuture-java.util.concurrent.CompletableFuture- > [2] > https://github.com/ReactiveX/RxJava/blob/3.x/src/main/java/io/reactivex/rxjava3/internal/jdk8/CompletableFromCompletionStage.java > > On Thu, Apr 1, 2021 at 1:29 PM Ivan Pavlukhin <vololo...@gmail.com> wrote: > >> Andrey, >> >> > Reactive abstractions look more suitable for Queries rather than >> > cache/table async operations and don't offer the power of chaining like >> > CompletableStage. >> >> Could you please elaborate what capabilities do you mean? AFAIK there >> are quite powerful APIs for singular reactive abstractions as well. >> E.g. [1]. >> >> [1] >> https://projectreactor.io/docs/core/release/api/reactor/core/publisher/Mono.html >> >> 2021-04-01 12:33 GMT+03:00, Andrey Mashenkov >> <andrey.mashen...@gmail.com>: >> > Val, >> > I just complain JDK CompletableFuture itself is not ideal, but already >> > implemented, well-known and tested. >> > It still a good alternative compared to custom future implementation to >> me. >> > >> > Ok, I feel most of us agree with CompletableFuture as a replacement for >> > custom IgniteFuture. >> > Let's try to use it, but keep in mind that we MUST return a defective >> copy >> > (via copy() or minimalStage()) to user to prevent misusage on the user >> > side. >> > It would be nice if we'll follow the same requirement in our internal >> code, >> > e.g. if a component returns a future that further can be used in other >> > components, especially in custom plugins. >> > >> > Ivan, thanks for the example. >> > Reactive abstractions look more suitable for Queries rather than >> > cache/table async operations and don't offer the power of chaining like >> > CompletableStage. >> > AFAIK, guys who involved in SQL engine development based on Calcite >> already >> > use reactive patterns. >> > >> > >> > On Thu, Apr 1, 2021 at 3:15 AM Ivan Pavlukhin <vololo...@gmail.com> >> wrote: >> > >> >> Folks, >> >> >> >> Regarding Reactive abstractions. While it might look too complex for >> >> simple KV cases it can be quite powerful for queries. Also there are >> >> known solutions for cancellation, backpressure and flow control. It >> >> can greatly simplify things for users familiar with Reactive >> >> programming rather than learning Ignite-specific Query/QueryCursor >> >> API. >> >> >> >> Also it looks like there are well-defined semantics [1]. E.g. >> >> cancellation seems to be defined much better than for >> >> CompletableFuture. >> >> >> >> [1] >> >> https://github.com/reactive-streams/reactive-streams-jvm#specification >> >> >> >> 2021-03-31 21:30 GMT+03:00, Valentin Kulichenko < >> >> valentin.kuliche...@gmail.com>: >> >> > Hi Andrey, >> >> > >> >> > Please see below. >> >> > >> >> > -Val >> >> > >> >> > On Wed, Mar 31, 2021 at 7:55 AM Andrey Mashenkov >> >> > <andrey.mashen...@gmail.com> >> >> > wrote: >> >> > >> >> >> CompletableFuture cancellation will not work as many users >> >> >> expected. >> >> >> Javadoc says: >> >> >> /* Since (unlike {@link FutureTask}) this class has no direct >> >> >> * control over the computation that causes it to be completed, >> >> >> * cancellation is treated as just another form of exceptional >> >> >> * completion. >> >> >> */ >> >> >> >> >> > >> >> > Let's not make assumptions about the expectations of the users. >> >> > That's >> >> > exactly why I initially leaned towards a custom interface as well, >> >> > but >> >> > that's a mistake. >> >> > Indeed, this contract might look weird to us, because the current >> >> > version >> >> > of Ignite behaves differently. However, there are much more >> >> > developers >> >> > using CompletableFuture and other standard async frameworks, than >> >> > developers using the async functionality of Ignite. Therefore, our >> >> > intuitions can easily be wrong. >> >> > >> >> > >> >> >> Completion of a child future doesn't trigger the completion of a >> >> >> parent. >> >> >> So, we will need to extend the future anyway. >> >> >> >> >> > >> >> > First of all, as Pavel mentioned, you can attach your own listener >> >> > before >> >> > returning a CompletableFuture to the user. You don't need to extend. >> >> > Second of all, there is still a discussion to be had on whether the >> >> parent >> >> > needs to be completed. I don't actually think it's obvious, and most >> >> likely >> >> > it's case by case. With CompletableFuture you have enough >> >> > flexibility >> >> > to >> >> > control the behavior. >> >> > >> >> > >> >> >> >> >> >> Also, cancel() method contract differs from IgniteFuture in 2.0, >> >> >> Completable method return true if the future was cancelled, >> >> >> but IgniteFuture return true only if it wasn't cancel prior the >> >> >> call. >> >> >> Thus, if cancel() was called twice we will have different results >> >> >> for >> >> >> CompletableFuture and IgniteFuture, >> >> >> that makes CompletableFuture barely usable for our internal >> >> >> purposes. >> >> >> >> >> > >> >> > It doesn't really matter how IgniteFuture in 2.0 behaves. It was >> >> > created >> >> > long before continuations and other async concepts became mainstream >> >> > (in >> >> > Java world at least). >> >> > Also, we don't have to use it for internal purposes, of course. I'm >> >> > only >> >> > talking about public APIs. >> >> > >> >> > >> >> >> >> >> >> BTW, CompletableFuture.anyOf() still can be used, see >> >> >> CompletionStage.toCompletableFuture() contract. >> >> >> >> >> > >> >> > In my view, this actually kills the idea of a custom future. >> Basically, >> >> > the proposal is to introduce a custom entity to restrict access to >> some >> >> of >> >> > the CompletableFuture methods, but then allow to convert this custom >> >> entity >> >> > to a CompletableFuture that has all the methods. This makes zero >> >> > sense >> >> > to >> >> > me. >> >> > >> >> > >> >> >> >> >> >> The more I learn about CompletableFuture the stronger my opinion >> about >> >> >> overriding it. >> >> >> >> >> >> >> >> >> On Wed, Mar 31, 2021 at 9:31 AM Denis Garus <garus....@gmail.com> >> >> wrote: >> >> >> >> >> >> > > Stripping them from such functionality, which they are used to, >> is >> >> >> > > most >> >> >> > likely a bad idea. >> >> >> > >> >> >> > Completely agree with this point of view. >> >> >> > Moreover, a user can pass CompletableFuture to another library to >> do >> >> >> > any >> >> >> > manipulations. >> >> >> > So if we want to introduce our class instead of the java class, >> >> >> > we >> >> >> > should >> >> >> > have solid arguments; >> >> >> > otherwise, it can be a reason for irritation. >> >> >> > >> >> >> > ср, 31 мар. 2021 г. в 09:06, Pavel Tupitsyn <ptupit...@apache.org >> >: >> >> >> > >> >> >> > > Val, >> >> >> > > >> >> >> > > > we can have an IgniteFuture that extends CompletableFuture. >> >> >> > > > This might be useful if want the cancel() operation to cancel >> >> >> > > > the >> >> >> > > > underlying operation >> >> >> > > >> >> >> > > I think we can subscribe to the cancellation of the >> >> CompletableFuture >> >> >> > > and cancel the underlying operation without an extra class, >> >> >> > > something like >> >> >> > > >> >> >> > > fut.exceptionally(t -> { >> >> >> > > if (t instanceof CancellationException) { >> >> >> > > // Cancel Ignite operation >> >> >> > > } >> >> >> > > }); >> >> >> > > >> >> >> > > On Wed, Mar 31, 2021 at 7:45 AM Valentin Kulichenko < >> >> >> > > valentin.kuliche...@gmail.com> wrote: >> >> >> > > >> >> >> > > > These are actually some interesting points. As I'm thinking >> more >> >> >> about >> >> >> > > > this, I'm leaning towards changing my opinion and voting for >> the >> >> >> > > > CompletableFuture. Here is my reasoning. >> >> >> > > > >> >> >> > > > First, it's important to keep in mind that CompletableFuture >> >> >> > > > is >> >> not >> >> >> an >> >> >> > > > interface that we will implement, it's an implemented class. >> >> >> Therefore, >> >> >> > > > some of the concerns around complete() and cancel() method >> >> >> > > > are >> >> >> > > > not >> >> >> > really >> >> >> > > > relevant -- it's not up to us how these methods behave, >> >> >> > > > they're >> >> >> already >> >> >> > > > implemented. >> >> >> > > > >> >> >> > > > Second, CompletableFuture does provide some useful >> functionality >> >> >> (anyOf >> >> >> > > is >> >> >> > > > one of the examples). I can even envision users wanting to >> >> complete >> >> >> the >> >> >> > > > future under certain circumstances, e.g. after a timeout, >> >> >> > > > using >> >> >> > > > the completeOnTimeout method. Stripping them from such >> >> >> > > > functionality, >> >> >> > > which >> >> >> > > > they are used to, is most likely a bad idea. >> >> >> > > > >> >> >> > > > And finally, we can have an IgniteFuture that extends >> >> >> > CompletableFuture. >> >> >> > > > This might be useful if want the cancel() operation to cancel >> >> >> > > > the >> >> >> > > > underlying operation. This way we keep all the functionality >> >> >> > > > of >> >> >> > > > CompletableFuture while keeping a certain amount of >> >> >> > > > flexibility >> >> for >> >> >> > > > specific cases. >> >> >> > > > >> >> >> > > > Thoughts? >> >> >> > > > >> >> >> > > > -Val >> >> >> > > > >> >> >> > > > >> >> >> > > > On Tue, Mar 30, 2021 at 5:36 AM Denis Garus >> >> >> > > > <garus....@gmail.com> >> >> >> > wrote: >> >> >> > > > >> >> >> > > > > > Completing future from outside will never respect other >> >> >> subscribers >> >> >> > > > that >> >> >> > > > > > may expect other guatantees. >> >> >> > > > > >> >> >> > > > > For example, if we talk about public API like IgniteCache, >> >> >> > > > > what >> >> >> > > > subscribers >> >> >> > > > > may expect other guatantees? >> >> >> > > > > IMHO, the best solution is to get the well-known standard >> >> >> > > > > interface >> >> >> > to >> >> >> > > a >> >> >> > > > > user, and he will be happy. >> >> >> > > > > >> >> >> > > > > But when we talk about internal classes like "exchange >> future" >> >> >> > > > > they >> >> >> > > could >> >> >> > > > > be custom futures if convenient. >> >> >> > > > > >> >> >> > > > > вт, 30 мар. 2021 г. в 15:25, Atri Sharma <a...@apache.org>: >> >> >> > > > > >> >> >> > > > > > IMO the only way Ignite should cancel computations is iff >> >> >> > > > > > cancel >> >> >> > > method >> >> >> > > > > is >> >> >> > > > > > invoked, not implicitly if complete is invoked. >> >> >> > > > > > >> >> >> > > > > > On Tue, 30 Mar 2021 at 4:58 PM, Denis Garus >> >> >> > > > > > <garus....@gmail.com >> >> >> > >> >> >> > > > wrote: >> >> >> > > > > > >> >> >> > > > > > > Hello! >> >> >> > > > > > > >> >> >> > > > > > > > Let's say a user started a compute with fut = >> >> >> > > > compute.runAsync(task); >> >> >> > > > > > > > and now calls fut.complete(someVal); Does this mean >> that >> >> >> Ignite >> >> >> > > no >> >> >> > > > > > longer >> >> >> > > > > > > needs to execute the task? >> >> >> > > > > > > > If the task is currently running, does it need to be >> >> >> canceled? >> >> >> > > > > > > >> >> >> > > > > > > Yes, this case looks like Ignite should cancel >> >> >> > > > > > > computations >> >> >> > > because a >> >> >> > > > > > user >> >> >> > > > > > > wants to complete the future. Why not? >> >> >> > > > > > > If there will be an opportunity to cancel a future, why >> is >> >> it >> >> >> > > > > > > a >> >> >> > bad >> >> >> > > > > > option >> >> >> > > > > > > to finish a future through a complete() method? >> >> >> > > > > > > >> >> >> > > > > > > > If you look at Ignite-2 code, you may found a number >> >> >> > > > > > > > of >> >> >> places >> >> >> > > > where >> >> >> > > > > we >> >> >> > > > > > > return e.g. exchange futures or partition release >> futures. >> >> >> > > > > > > > Assume the impact if we will return CompletableFuture >> >> >> instead, >> >> >> > > > which >> >> >> > > > > > can >> >> >> > > > > > > be completed in 3-rd party plugin by mistake? >> >> >> > > > > > > >> >> >> > > > > > > If exchange futures or partition release futures can be >> >> >> returned >> >> >> > to >> >> >> > > > > 3-rd >> >> >> > > > > > > party plugin by mistake, it is poor encapsulation. >> >> >> > > > > > > And if it will be IgniteFuter rather than >> CompletedFuture, >> >> >> > anyway, >> >> >> > > > this >> >> >> > > > > > can >> >> >> > > > > > > harm. >> >> >> > > > > > > >> >> >> > > > > > > вт, 30 мар. 2021 г. в 13:14, Andrey Mashenkov < >> >> >> > > > > > andrey.mashen...@gmail.com >> >> >> > > > > > > >: >> >> >> > > > > > > >> >> >> > > > > > > > Guys, >> >> >> > > > > > > > >> >> >> > > > > > > > I want to remember there is one more point to pay >> >> attention >> >> >> to. >> >> >> > > > > > > > Extending Future and CompletableStage is more than >> >> >> > > > > > > > just >> >> >> > prevents >> >> >> > > > > > > unexpected >> >> >> > > > > > > > behavior if a user completed the future. >> >> >> > > > > > > > >> >> >> > > > > > > > First of all, it helps us to write safer code as we >> >> >> > > > > > > > won't >> >> a >> >> >> > > method >> >> >> > > > > > > contract >> >> >> > > > > > > > exposed such methods as to a user as to a developer. >> >> >> > > > > > > > If you look at Ignite-2 code, you may found a number >> >> >> > > > > > > > of >> >> >> places >> >> >> > > > where >> >> >> > > > > we >> >> >> > > > > > > > return e.g. exchange futures or partition release >> >> >> > > > > > > > futures. >> >> >> > > > > > > > Assume the impact if we will return CompletableFuture >> >> >> instead, >> >> >> > > > which >> >> >> > > > > > can >> >> >> > > > > > > be >> >> >> > > > > > > > completed in 3-rd party plugin by mistake? >> >> >> > > > > > > > >> >> >> > > > > > > > The suggested approach allows us to don't bother if a >> >> >> > > > > CompletableFuture >> >> >> > > > > > > has >> >> >> > > > > > > > to be wrapped or not. >> >> >> > > > > > > > >> >> >> > > > > > > > >> >> >> > > > > > > > On Tue, Mar 30, 2021 at 12:22 PM Alexey Goncharuk < >> >> >> > > > > > > > alexey.goncha...@gmail.com> wrote: >> >> >> > > > > > > > >> >> >> > > > > > > > > Ivan, >> >> >> > > > > > > > > >> >> >> > > > > > > > > My concern with the concept of a user completing >> >> >> > > > > > > > > the >> >> >> > > > > > > > > future >> >> >> > > > > returned >> >> >> > > > > > > from >> >> >> > > > > > > > > Ignite public API is that it is unclear how to >> >> >> > > > > > > > > interpret >> >> >> this >> >> >> > > > > action >> >> >> > > > > > > > (this >> >> >> > > > > > > > > backs Val's message). >> >> >> > > > > > > > > Let's say a user started a compute with fut = >> >> >> > > > > compute.runAsync(task); >> >> >> > > > > > > and >> >> >> > > > > > > > > now calls fut.complete(someVal); Does this mean >> >> >> > > > > > > > > that >> >> >> > > > > > > > > Ignite >> >> >> > no >> >> >> > > > > longer >> >> >> > > > > > > > needs >> >> >> > > > > > > > > to execute the task? If the task is currently >> running, >> >> >> > > > > > > > > does >> >> >> > it >> >> >> > > > need >> >> >> > > > > > to >> >> >> > > > > > > be >> >> >> > > > > > > > > canceled? >> >> >> > > > > > > > > >> >> >> > > > > > > > > Using CompletableFuture.anyOf() is a good >> >> >> > > > > > > > > instrument >> >> >> > > > > > > > > in >> >> >> this >> >> >> > > case >> >> >> > > > > > > because >> >> >> > > > > > > > > it makes the 'first future wins' contract explicit >> >> >> > > > > > > > > in >> >> the >> >> >> > code. >> >> >> > > > > > Besides >> >> >> > > > > > > > > that, the point regarding the cancel() method is >> >> >> > > > > > > > > valid, >> >> >> > > > > > > > > and >> >> >> > we >> >> >> > > > will >> >> >> > > > > > > need >> >> >> > > > > > > > > some custom mechanics to cancel a computation, so a >> >> >> > > > > > > > > custom >> >> >> > > > > interface >> >> >> > > > > > > that >> >> >> > > > > > > > > simply extends both Future and CompletableStage >> >> >> > > > > > > > > seems >> >> >> > > reasonable >> >> >> > > > to >> >> >> > > > > > me. >> >> >> > > > > > > > > >> >> >> > > > > > > > > --AG >> >> >> > > > > > > > > >> >> >> > > > > > > > > пн, 29 мар. 2021 г. в 09:12, Ivan Pavlukhin < >> >> >> > > vololo...@gmail.com >> >> >> > > > >: >> >> >> > > > > > > > > >> >> >> > > > > > > > > > Val, >> >> >> > > > > > > > > > >> >> >> > > > > > > > > > There were enough hype around Reactive >> >> >> > > > > > > > > > programming >> >> past >> >> >> > > years. >> >> >> > > > I >> >> >> > > > > > > > > > remind a lot of talks about RxJava. And I suppose >> it >> >> >> worth >> >> >> > to >> >> >> > > > > > > consider >> >> >> > > > > > > > > > it. But it requires some time to study modern >> trends >> >> to >> >> >> > make >> >> >> > > a >> >> >> > > > > > > choice. >> >> >> > > > > > > > > > So far I am not ready to facilitate Reactive API >> for >> >> >> Ignite >> >> >> > > 3. >> >> >> > > > > > > > > > >> >> >> > > > > > > > > > Regarding CompletableFuture. >> >> >> > > > > > > > > > >> >> >> > > > > > > > > > > The point is that currently a future returned >> from >> >> >> > > > > > > > > > > any >> >> >> of >> >> >> > > > > > Ignite's >> >> >> > > > > > > > > async >> >> >> > > > > > > > > > > operations is supposed to be completed with a >> >> >> > > > > > > > > > > value >> >> >> only >> >> >> > by >> >> >> > > > > > Ignite >> >> >> > > > > > > > > > itself, >> >> >> > > > > > > > > > > not by the user. If we follow the same approach >> in >> >> >> Ignite >> >> >> > > 3, >> >> >> > > > > > > > returning >> >> >> > > > > > > > > > > CompletableFuture is surely wrong in my view. >> >> >> > > > > > > > > > >> >> >> > > > > > > > > > My first thoughts was similar. But later I >> >> >> > > > > > > > > > thought >> >> what >> >> >> > > > > > > > > > a >> >> >> > > user >> >> >> > > > > > would >> >> >> > > > > > > > > > like do with returned future. And one of cases I >> >> >> > > > > > > > > > imagined >> >> >> > > was a >> >> >> > > > > > case >> >> >> > > > > > > > > > of alternative result. E.g. a user uses Ignite >> >> >> > > > > > > > > > and >> >> >> another >> >> >> > > data >> >> >> > > > > > > source >> >> >> > > > > > > > > > in his application. He wants to use a value >> >> >> > > > > > > > > > arrived >> >> >> faster. >> >> >> > > He >> >> >> > > > > > > > > > combines 2 futures like >> >> >> > > > > > > > > > CompletableFuture.anyOf(...). >> >> >> > > > > Consequently >> >> >> > > > > > > > > > even if we prohibit >> >> >> > > > > > > > > > CompletableFuture.complete(...) >> >> >> > > explicitly >> >> >> > > > > then >> >> >> > > > > > > it >> >> >> > > > > > > > > > will be possible to create a combination that >> >> >> > > > > > > > > > will >> >> >> > > > > > > > > > allow >> >> >> > > > > premature >> >> >> > > > > > > > > > future completion. After all generally >> >> >> > > > > > > > > > CompletableFuture >> >> >> > is a >> >> >> > > > > > > > > > placeholder for async computaion result and if a >> >> >> > > > > > > > > > user >> >> >> wants >> >> >> > > to >> >> >> > > > > > > > > > substitute result returned from Ignite why should >> we >> >> >> > disallow >> >> >> > > > him >> >> >> > > > > > to >> >> >> > > > > > > > > > do it? >> >> >> > > > > > > > > > >> >> >> > > > > > > > > > Also I found one more suspicious thing with >> >> >> > > CompletableFuture. >> >> >> > > > As >> >> >> > > > > > it >> >> >> > > > > > > > > > is a concrete class it implements a cancel() >> method. >> >> >> > > > > > > > > > And >> >> >> > as I >> >> >> > > > see >> >> >> > > > > > the >> >> >> > > > > > > > > > implementation does not try to cancel underlying >> >> >> > > computations. >> >> >> > > > Is >> >> >> > > > > > not >> >> >> > > > > > > > > > it a problem? >> >> >> > > > > > > > > > >> >> >> > > > > > > > > > 2021-03-29 7:30 GMT+03:00, Valentin Kulichenko < >> >> >> > > > > > > > > > valentin.kuliche...@gmail.com>: >> >> >> > > > > > > > > > > Ivan, >> >> >> > > > > > > > > > > >> >> >> > > > > > > > > > > It's not really about the "harm", but more >> >> >> > > > > > > > > > > about >> >> >> > > > > > > > > > > "what >> >> >> > > should >> >> >> > > > > we >> >> >> > > > > > do >> >> >> > > > > > > > if >> >> >> > > > > > > > > > this >> >> >> > > > > > > > > > > method is called?". Imagine the following code: >> >> >> > > > > > > > > > > >> >> >> > > > > > > > > > > CompletableFuture<String> fut = >> >> >> > > > > > > > > > > cache.getAsync(key); >> >> >> > > > > > > > > > > fut.complete("something"); >> >> >> > > > > > > > > > > >> >> >> > > > > > > > > > > What should happen in this case? >> >> >> > > > > > > > > > > >> >> >> > > > > > > > > > > The point is that currently a future returned >> from >> >> >> > > > > > > > > > > any >> >> >> of >> >> >> > > > > > Ignite's >> >> >> > > > > > > > > async >> >> >> > > > > > > > > > > operations is supposed to be completed with a >> >> >> > > > > > > > > > > value >> >> >> only >> >> >> > by >> >> >> > > > > > Ignite >> >> >> > > > > > > > > > itself, >> >> >> > > > > > > > > > > not by the user. If we follow the same approach >> in >> >> >> Ignite >> >> >> > > 3, >> >> >> > > > > > > > returning >> >> >> > > > > > > > > > > CompletableFuture is surely wrong in my view. >> >> >> > > > > > > > > > > >> >> >> > > > > > > > > > > At the same time, if we take a fundamentally >> >> >> > > > > > > > > > > different >> >> >> > > route >> >> >> > > > > with >> >> >> > > > > > > the >> >> >> > > > > > > > > > async >> >> >> > > > > > > > > > > APIs, this whole discussion might become >> >> >> > > > > > > > > > > irrelevant. >> >> >> For >> >> >> > > > > example, >> >> >> > > > > > > can >> >> >> > > > > > > > > you >> >> >> > > > > > > > > > > elaborate on your thinking around the reactive >> >> >> > > > > > > > > > > API? >> >> >> > > > > > > > > > > Do >> >> >> > you >> >> >> > > > have >> >> >> > > > > > any >> >> >> > > > > > > > > > > specifics in mind? >> >> >> > > > > > > > > > > >> >> >> > > > > > > > > > > -Val >> >> >> > > > > > > > > > > >> >> >> > > > > > > > > > > On Sat, Mar 27, 2021 at 9:18 PM Ivan Pavlukhin >> >> >> > > > > > > > > > > < >> >> >> > > > > > > vololo...@gmail.com> >> >> >> > > > > > > > > > wrote: >> >> >> > > > > > > > > > > >> >> >> > > > > > > > > > >> > The methods below shouldn't be accessible >> >> >> > > > > > > > > > >> > for >> >> >> > > > > > > > > > >> > user: >> >> >> > > > > > > > > > >> > complete() >> >> >> > > > > > > > > > >> > completeExceptionaly() >> >> >> > > > > > > > > > >> >> >> >> > > > > > > > > > >> Folks, in case of user-facing API, do you >> >> >> > > > > > > > > > >> think >> >> >> > > > > > > > > > >> there >> >> >> > is a >> >> >> > > > > real >> >> >> > > > > > > harm >> >> >> > > > > > > > > > >> in allowing a user to manually "complete" a >> >> >> > > > > > > > > > >> future? >> >> >> > > > > > > > > > >> I >> >> >> > > > suppose >> >> >> > > > > a >> >> >> > > > > > > user >> >> >> > > > > > > > > > >> employs some post-processing for future >> >> >> > > > > > > > > > >> results >> >> >> > > > > > > > > > >> and >> >> >> > > > > potentially >> >> >> > > > > > > > wants >> >> >> > > > > > > > > > >> to have control of these results as well. E.g. >> >> >> premature >> >> >> > > > > > > completion >> >> >> > > > > > > > in >> >> >> > > > > > > > > > >> case when a result is no longer needed is >> >> >> > > > > > > > > > >> possible >> >> >> > usage. >> >> >> > > > > > > > > > >> >> >> >> > > > > > > > > > >> Also I thinkg it might be a good time to >> >> >> > > > > > > > > > >> ponder >> >> >> > > > > > > > > > >> about >> >> >> > > > > > > Future/Promise >> >> >> > > > > > > > > > >> APIs in general. Why such API is our choice? >> >> >> > > > > > > > > > >> Can >> >> >> > > > > > > > > > >> we >> >> >> > choose >> >> >> > > > > e.g. >> >> >> > > > > > > > > > >> Reactive API style instead? >> >> >> > > > > > > > > > >> >> >> >> > > > > > > > > > >> 2021-03-27 0:33 GMT+03:00, Valentin Kulichenko >> >> >> > > > > > > > > > >> < >> >> >> > > > > > > > > > >> valentin.kuliche...@gmail.com>: >> >> >> > > > > > > > > > >> > Andrey, >> >> >> > > > > > > > > > >> > >> >> >> > > > > > > > > > >> > I see. So in a nutshell, you're saying that >> >> >> > > > > > > > > > >> > we >> >> >> > > > > > > > > > >> > want >> >> >> to >> >> >> > > > > return >> >> >> > > > > > a >> >> >> > > > > > > > > future >> >> >> > > > > > > > > > >> that >> >> >> > > > > > > > > > >> > the user's code is not allowed to complete. >> >> >> > > > > > > > > > >> > In >> >> >> > > > > > > > > > >> > this >> >> >> > > case, >> >> >> > > > I >> >> >> > > > > > > think >> >> >> > > > > > > > > it's >> >> >> > > > > > > > > > >> > clear that CompletableFuture is not what we >> >> >> > > > > > > > > > >> > need. >> >> >> > > > > > > > > > >> > We >> >> >> > > > > actually >> >> >> > > > > > > > need a >> >> >> > > > > > > > > > >> > NonCompletableFuture :) >> >> >> > > > > > > > > > >> > >> >> >> > > > > > > > > > >> > My vote is for the custom interface. >> >> >> > > > > > > > > > >> > >> >> >> > > > > > > > > > >> > -Val >> >> >> > > > > > > > > > >> > >> >> >> > > > > > > > > > >> > On Fri, Mar 26, 2021 at 2:25 AM Andrey >> >> >> > > > > > > > > > >> > Mashenkov >> >> >> > > > > > > > > > >> > <andrey.mashen...@gmail.com> >> >> >> > > > > > > > > > >> > wrote: >> >> >> > > > > > > > > > >> > >> >> >> > > > > > > > > > >> >> Val, >> >> >> > > > > > > > > > >> >> >> >> >> > > > > > > > > > >> >> The methods below shouldn't be accessible >> >> >> > > > > > > > > > >> >> for >> >> >> > > > > > > > > > >> >> user: >> >> >> > > > > > > > > > >> >> complete() >> >> >> > > > > > > > > > >> >> completeExceptionaly() >> >> >> > > > > > > > > > >> >> >> >> >> > > > > > > > > > >> >> Returning CompletableFuture we must always >> >> >> > > > > > > > > > >> >> make >> >> a >> >> >> > copy >> >> >> > > to >> >> >> > > > > > > prevent >> >> >> > > > > > > > > the >> >> >> > > > > > > > > > >> >> original future from being completed by >> >> >> > > > > > > > > > >> >> mistake. >> >> >> > > > > > > > > > >> >> I think it will NOT be enough to do that >> >> returing >> >> >> the >> >> >> > > > > future >> >> >> > > > > > to >> >> >> > > > > > > > the >> >> >> > > > > > > > > > >> >> end-user, but from every critical module to >> >> >> > > > > > > > > > >> >> the >> >> >> > outside >> >> >> > > > of >> >> >> > > > > > the >> >> >> > > > > > > > > > module, >> >> >> > > > > > > > > > >> >> e.g. to plugins. The impact of disclosing >> >> >> > > ExchangeFuture, >> >> >> > > > > > > > > > >> >> PartitionReleaseFuture to plugins may be >> >> serious. >> >> >> > > > > > > > > > >> >> >> >> >> > > > > > > > > > >> >> IgniteFuture<T> extends Future<T>, >> >> >> CompletionStage<T> >> >> >> > > > which >> >> >> > > > > > > > > > >> >> implementation >> >> >> > > > > > > > > > >> >> will just wrap CompletableFuture these >> >> >> > > > > > > > > > >> >> issues >> >> >> > > > > > > > > > >> >> will >> >> >> be >> >> >> > > > > > resolved >> >> >> > > > > > > in >> >> >> > > > > > > > > > >> natural >> >> >> > > > > > > > > > >> >> way. >> >> >> > > > > > > > > > >> >> In addition we can force >> toCompletableFuture() >> >> >> method >> >> >> > > to >> >> >> > > > > > > return a >> >> >> > > > > > > > > > >> >> defensive >> >> >> > > > > > > > > > >> >> copy(), that resolves the last concern. >> >> >> > > > > > > > > > >> >> >> >> >> > > > > > > > > > >> >> >> >> >> > > > > > > > > > >> >> On Fri, Mar 26, 2021 at 11:38 AM Konstantin >> >> Orlov >> >> >> > > > > > > > > > >> >> <kor...@gridgain.com> >> >> >> > > > > > > > > > >> >> wrote: >> >> >> > > > > > > > > > >> >> >> >> >> > > > > > > > > > >> >> > CompletableFuture seems a better option >> >> >> > > > > > > > > > >> >> > to >> >> >> > > > > > > > > > >> >> > me. >> >> >> > > > > > > > > > >> >> > >> >> >> > > > > > > > > > >> >> > -- >> >> >> > > > > > > > > > >> >> > Regards, >> >> >> > > > > > > > > > >> >> > Konstantin Orlov >> >> >> > > > > > > > > > >> >> > >> >> >> > > > > > > > > > >> >> > >> >> >> > > > > > > > > > >> >> > >> >> >> > > > > > > > > > >> >> > >> >> >> > > > > > > > > > >> >> > > On 26 Mar 2021, at 11:07, Pavel >> >> >> > > > > > > > > > >> >> > > Tupitsyn >> < >> >> >> > > > > > > > ptupit...@apache.org >> >> >> > > > > > > > > > >> >> >> > > > > > > > > > >> >> > > wrote: >> >> >> > > > > > > > > > >> >> > > >> >> >> > > > > > > > > > >> >> > > On the one hand, I agree with Alexey. >> >> >> > > > > > > > > > >> >> > > CompletableFuture has complete* methods >> >> which >> >> >> > > should >> >> >> > > > > not >> >> >> > > > > > be >> >> >> > > > > > > > > > >> available >> >> >> > > > > > > > > > >> >> to >> >> >> > > > > > > > > > >> >> > > the user code. >> >> >> > > > > > > > > > >> >> > > This can be solved with a simple >> interface >> >> >> > > > > > > > > > >> >> > > like >> >> >> > we >> >> >> > > do >> >> >> > > > > in >> >> >> > > > > > > Thin >> >> >> > > > > > > > > > >> Client: >> >> >> > > > > > > > > > >> >> > > IgniteClientFuture<T> extends >> >> >> > > > > > > > > > >> >> > > Future<T>, >> >> >> > > > > > CompletionStage<T> >> >> >> > > > > > > > > > >> >> > > >> >> >> > > > > > > > > > >> >> > > >> >> >> > > > > > > > > > >> >> > > On the other hand: >> >> >> > > > > > > > > > >> >> > > - CompletionStage has >> >> >> > > > > > > > > > >> >> > > toCompletableFuture >> >> >> anyway >> >> >> > > > > (rather >> >> >> > > > > > > > weird) >> >> >> > > > > > > > > > >> >> > > - Other libraries use CompletableFuture >> >> >> > > > > > > > > > >> >> > > and >> >> >> > > > > > > > > > >> >> > > it >> >> >> > > seems >> >> >> > > > to >> >> >> > > > > > be >> >> >> > > > > > > > fine >> >> >> > > > > > > > > > >> >> > > - Using CompletableFuture is the >> >> >> > > > > > > > > > >> >> > > simplest >> >> >> > approach >> >> >> > > > > > > > > > >> >> > > >> >> >> > > > > > > > > > >> >> > > >> >> >> > > > > > > > > > >> >> > > So I lean towards CompletableFuture >> >> >> > > > > > > > > > >> >> > > too. >> >> >> > > > > > > > > > >> >> > > >> >> >> > > > > > > > > > >> >> > > On Fri, Mar 26, 2021 at 10:46 AM Alexey >> >> >> > Kukushkin < >> >> >> > > > > > > > > > >> >> > kukushkinale...@gmail.com> >> >> >> > > > > > > > > > >> >> > > wrote: >> >> >> > > > > > > > > > >> >> > > >> >> >> > > > > > > > > > >> >> > >> I do not like Java's CompletableFuture >> >> >> > > > > > > > > > >> >> > >> and >> >> >> > prefer >> >> >> > > > our >> >> >> > > > > > own >> >> >> > > > > > > > > Future >> >> >> > > > > > > > > > >> >> > (revised >> >> >> > > > > > > > > > >> >> > >> IgniteFuture). >> >> >> > > > > > > > > > >> >> > >> >> >> >> > > > > > > > > > >> >> > >> My understanding of the Future (or >> >> >> > > > > > > > > > >> >> > >> Promise) >> >> >> > > pattern >> >> >> > > > in >> >> >> > > > > > > > general >> >> >> > > > > > > > > > is >> >> >> > > > > > > > > > >> >> having >> >> >> > > > > > > > > > >> >> > >> two separate APIs: >> >> >> > > > > > > > > > >> >> > >> >> >> >> > > > > > > > > > >> >> > >> 1. Server-side: create, set result, >> >> >> > > > > > > > > > >> >> > >> raise >> >> >> > error, >> >> >> > > > > > cancel >> >> >> > > > > > > > from >> >> >> > > > > > > > > > >> >> > >> server. >> >> >> > > > > > > > > > >> >> > >> 2. Client-side: get result, handle >> >> >> > > > > > > > > > >> >> > >> error, >> >> >> > cancel >> >> >> > > > > from >> >> >> > > > > > > > client >> >> >> > > > > > > > > > >> >> > >> >> >> >> > > > > > > > > > >> >> > >> Java's CompletableFuture looks like >> >> >> > > > > > > > > > >> >> > >> both >> >> the >> >> >> > > > > client-side >> >> >> > > > > > > and >> >> >> > > > > > > > > > >> >> > >> server-side API. The "Completeable" >> >> >> > > > > > > > > > >> >> > >> prefix >> >> >> > > > > > > > > > >> >> > >> in >> >> >> > the >> >> >> > > > name >> >> >> > > > > > is >> >> >> > > > > > > > > > already >> >> >> > > > > > > > > > >> >> > confusing >> >> >> > > > > > > > > > >> >> > >> for a client since it cannot >> >> >> > > > > > > > > > >> >> > >> "complete" >> >> >> > > > > > > > > > >> >> > >> an >> >> >> > > > operation, >> >> >> > > > > > > only a >> >> >> > > > > > > > > > >> >> > >> server >> >> >> > > > > > > > > > >> >> can. >> >> >> > > > > > > > > > >> >> > >> >> >> >> > > > > > > > > > >> >> > >> I would create our own IgniteFuture >> >> >> > > > > > > > > > >> >> > >> adding >> >> >> > > > client-side >> >> >> > > > > > > > > > >> functionality >> >> >> > > > > > > > > > >> >> we >> >> >> > > > > > > > > > >> >> > >> currently miss (like client-side >> >> >> cancellation). >> >> >> > > > > > > > > > >> >> > >> >> >> >> > > > > > > > > > >> >> > >> >> >> >> > > > > > > > > > >> >> > >> пт, 26 мар. 2021 г. в 01:08, Valentin >> >> >> > Kulichenko < >> >> >> > > > > > > > > > >> >> > >> valentin.kuliche...@gmail.com>: >> >> >> > > > > > > > > > >> >> > >> >> >> >> > > > > > > > > > >> >> > >>> Andrey, >> >> >> > > > > > > > > > >> >> > >>> >> >> >> > > > > > > > > > >> >> > >>> Can you compile a full list of these >> >> >> > > > > > > > > > >> >> > >>> risky >> >> >> > > methods, >> >> >> > > > > and >> >> >> > > > > > > > > > >> >> > >>> elaborate >> >> >> > > > > > > > > > >> >> > >>> on >> >> >> > > > > > > > > > >> >> > what >> >> >> > > > > > > > > > >> >> > >>> the risks are? >> >> >> > > > > > > > > > >> >> > >>> >> >> >> > > > > > > > > > >> >> > >>> Generally, CompletableFuture is a >> >> >> > > > > > > > > > >> >> > >>> much >> >> >> > > > > > > > > > >> >> > >>> better >> >> >> > > > option, >> >> >> > > > > > > > because >> >> >> > > > > > > > > > >> >> > >>> it's >> >> >> > > > > > > > > > >> >> > >>> standard. But we need to make sure it >> >> >> actually >> >> >> > > fits >> >> >> > > > > our >> >> >> > > > > > > > needs >> >> >> > > > > > > > > > >> >> > >>> and >> >> >> > > > > > > > > > >> >> > doesn't >> >> >> > > > > > > > > > >> >> > >>> do more harm than good. >> >> >> > > > > > > > > > >> >> > >>> >> >> >> > > > > > > > > > >> >> > >>> -Val >> >> >> > > > > > > > > > >> >> > >>> >> >> >> > > > > > > > > > >> >> > >>> On Thu, Mar 25, 2021 at 12:23 PM >> >> >> > > > > > > > > > >> >> > >>> Alexei >> >> >> > > Scherbakov >> >> >> > > > < >> >> >> > > > > > > > > > >> >> > >>> alexey.scherbak...@gmail.com> wrote: >> >> >> > > > > > > > > > >> >> > >>> >> >> >> > > > > > > > > > >> >> > >>>> I think both options are fine, but >> >> >> personally >> >> >> > > lean >> >> >> > > > > > > toward >> >> >> > > > > > > > > > >> >> > >>>> CompletableFuture. >> >> >> > > > > > > > > > >> >> > >>>> >> >> >> > > > > > > > > > >> >> > >>>> чт, 25 мар. 2021 г. в 17:56, Atri >> >> >> > > > > > > > > > >> >> > >>>> Sharma >> >> < >> >> >> > > > > > > a...@apache.org >> >> >> > > > > > > > >: >> >> >> > > > > > > > > > >> >> > >>>> >> >> >> > > > > > > > > > >> >> > >>>>> I would suggest using >> >> >> > > > > > > > > > >> >> > >>>>> CompletableFuture >> >> >> > > > > > > > > > >> >> > >>>>> -- >> >> >> I >> >> >> > > > don't >> >> >> > > > > > see >> >> >> > > > > > > a >> >> >> > > > > > > > > need >> >> >> > > > > > > > > > >> for >> >> >> > > > > > > > > > >> >> > >>>>> a >> >> >> > > > > > > > > > >> >> > >>>> custom >> >> >> > > > > > > > > > >> >> > >>>>> interface that is unique to us. >> >> >> > > > > > > > > > >> >> > >>>>> >> >> >> > > > > > > > > > >> >> > >>>>> It also allows a lower barrier for >> new >> >> >> > > > contributors >> >> >> > > > > > for >> >> >> > > > > > > > > > >> >> understanding >> >> >> > > > > > > > > > >> >> > >>>>> existing code >> >> >> > > > > > > > > > >> >> > >>>>> >> >> >> > > > > > > > > > >> >> > >>>>> On Thu, 25 Mar 2021, 20:18 Andrey >> >> >> Mashenkov, >> >> >> > < >> >> >> > > > > > > > > > >> >> > >>> andrey.mashen...@gmail.com >> >> >> > > > > > > > > > >> >> > >>>>> >> >> >> > > > > > > > > > >> >> > >>>>> wrote: >> >> >> > > > > > > > > > >> >> > >>>>> >> >> >> > > > > > > > > > >> >> > >>>>>> Hi Igniters, >> >> >> > > > > > > > > > >> >> > >>>>>> >> >> >> > > > > > > > > > >> >> > >>>>>> I'd like to start a discussion >> >> >> > > > > > > > > > >> >> > >>>>>> about >> >> >> > replacing >> >> >> > > > our >> >> >> > > > > > > > custom >> >> >> > > > > > > > > > >> >> > >>> IgniteFuture >> >> >> > > > > > > > > > >> >> > >>>>>> class with CompletableFuture - >> >> >> > > > > > > > > > >> >> > >>>>>> existed >> >> >> > > > > > > > > > >> >> > >>>>>> JDK >> >> >> > > class >> >> >> > > > > > > > > > >> >> > >>>>>> or rework it's implementation >> >> >> > > > > > > > > > >> >> > >>>>>> (like >> >> some >> >> >> > other >> >> >> > > > > > > products >> >> >> > > > > > > > > > done) >> >> >> > > > > > > > > > >> to >> >> >> > > > > > > > > > >> >> > >>>>>> a >> >> >> > > > > > > > > > >> >> > >>>>>> composition of CompletionStage and >> >> >> > > > > > > > > > >> >> > >>>>>> Future >> >> >> > > > > > interfaces. >> >> >> > > > > > > > > > >> >> > >>>>>> or maybe other option if you have >> any >> >> >> ideas. >> >> >> > > Do >> >> >> > > > > you? >> >> >> > > > > > > > > > >> >> > >>>>>> >> >> >> > > > > > > > > > >> >> > >>>>>> 1. The first approach pros and >> >> >> > > > > > > > > > >> >> > >>>>>> cons >> >> >> > > > > > > > > > >> >> > >>>>>> are >> >> >> > > > > > > > > > >> >> > >>>>>> + Well-known JDK class >> >> >> > > > > > > > > > >> >> > >>>>>> + Already implemented >> >> >> > > > > > > > > > >> >> > >>>>>> - It is a class, not an interface. >> >> >> > > > > > > > > > >> >> > >>>>>> - Expose some potentially harmful >> >> >> > > > > > > > > > >> >> > >>>>>> methods >> >> >> > like >> >> >> > > > > > > > > "complete()". >> >> >> > > > > > > > > > >> >> > >>>>>> >> >> >> > > > > > > > > > >> >> > >>>>>> On the other side, it has copy() >> >> >> > > > > > > > > > >> >> > >>>>>> method >> >> >> > > > > > > > > > >> >> > >>>>>> to >> >> >> > > > create >> >> >> > > > > > > > > defensive >> >> >> > > > > > > > > > >> copy >> >> >> > > > > > > > > > >> >> > >> and >> >> >> > > > > > > > > > >> >> > >>>>>> minimalCompletionStage() to >> >> >> > > > > > > > > > >> >> > >>>>>> restrict >> >> >> harmful >> >> >> > > > > method >> >> >> > > > > > > > usage. >> >> >> > > > > > > > > > >> >> > >>>>>> Thus, this look like an applicable >> >> >> solution, >> >> >> > > but >> >> >> > > > > we >> >> >> > > > > > > > should >> >> >> > > > > > > > > > be >> >> >> > > > > > > > > > >> >> > >> careful >> >> >> > > > > > > > > > >> >> > >>>>>> exposing internal future to the >> >> outside. >> >> >> > > > > > > > > > >> >> > >>>>>> >> >> >> > > > > > > > > > >> >> > >>>>>> 2. The second approach is to >> >> >> > > > > > > > > > >> >> > >>>>>> implement >> >> >> > > > > > > > > > >> >> > >>>>>> our >> >> >> > own >> >> >> > > > > > > interface >> >> >> > > > > > > > > > like >> >> >> > > > > > > > > > >> >> > >>>>>> the >> >> >> > > > > > > > > > >> >> > >>> next >> >> >> > > > > > > > > > >> >> > >>>>> one: >> >> >> > > > > > > > > > >> >> > >>>>>> >> >> >> > > > > > > > > > >> >> > >>>>>> interface IgniteFuture<T> extends >> >> >> > > > > > CompletableStage<T>, >> >> >> > > > > > > > > > >> Future<T> >> >> >> > > > > > > > > > >> >> > >>>>>> { >> >> >> > > > > > > > > > >> >> > >>>>>> } >> >> >> > > > > > > > > > >> >> > >>>>>> >> >> >> > > > > > > > > > >> >> > >>>>>> Pros and cons are >> >> >> > > > > > > > > > >> >> > >>>>>> + Our interfaces/classes contracts >> >> >> > > > > > > > > > >> >> > >>>>>> will >> >> >> > expose >> >> >> > > > an >> >> >> > > > > > > > > interface >> >> >> > > > > > > > > > >> >> > >>>>>> rather >> >> >> > > > > > > > > > >> >> > >>> than >> >> >> > > > > > > > > > >> >> > >>>>>> concrete implementation. >> >> >> > > > > > > > > > >> >> > >>>>>> + All methods are safe. >> >> >> > > > > > > > > > >> >> > >>>>>> - Some implementation is required. >> >> >> > > > > > > > > > >> >> > >>>>>> - CompletableStage has a method >> >> >> > > > > > toCompletableFuture() >> >> >> > > > > > > > and >> >> >> > > > > > > > > > can >> >> >> > > > > > > > > > >> be >> >> >> > > > > > > > > > >> >> > >>>>> converted >> >> >> > > > > > > > > > >> >> > >>>>>> to CompletableFuture. This should >> >> >> > > > > > > > > > >> >> > >>>>>> be >> >> >> > > supported. >> >> >> > > > > > > > > > >> >> > >>>>>> >> >> >> > > > > > > > > > >> >> > >>>>>> However, we still could wrap >> >> >> > CompletableFuture >> >> >> > > > and >> >> >> > > > > > > don't >> >> >> > > > > > > > > > >> >> > >>>>>> bother >> >> >> > > > > > > > > > >> >> > >> about >> >> >> > > > > > > > > > >> >> > >>>>>> creating a defensive copy. >> >> >> > > > > > > > > > >> >> > >>>>>> >> >> >> > > > > > > > > > >> >> > >>>>>> >> >> >> > > > > > > > > > >> >> > >>>>>> Other project experience: >> >> >> > > > > > > > > > >> >> > >>>>>> * Spotify uses CompletableFuture >> >> >> > > > > > > > > > >> >> > >>>>>> directly >> >> >> > [1]. >> >> >> > > > > > > > > > >> >> > >>>>>> * Redis goes the second approach >> >> >> > > > > > > > > > >> >> > >>>>>> [2] >> >> >> > > > > > > > > > >> >> > >>>>>> * Vertx explicitly extends >> >> >> CompletableFuture >> >> >> > > > [3]. >> >> >> > > > > > > > However, >> >> >> > > > > > > > > > >> >> > >>>>>> they >> >> >> > > > > > > > > > >> >> > >> have >> >> >> > > > > > > > > > >> >> > >>>>> custom >> >> >> > > > > > > > > > >> >> > >>>>>> future classes and a number of >> >> >> > > > > > > > > > >> >> > >>>>>> helpers >> >> >> that >> >> >> > > > could >> >> >> > > > > be >> >> >> > > > > > > > > > replaced >> >> >> > > > > > > > > > >> >> > >>>>>> with >> >> >> > > > > > > > > > >> >> > >>>>>> CompletableStage. Maybe it is just >> >> >> > > > > > > > > > >> >> > >>>>>> a >> >> >> > legacy.' >> >> >> > > > > > > > > > >> >> > >>>>>> >> >> >> > > > > > > > > > >> >> > >>>>>> Any thoughts? >> >> >> > > > > > > > > > >> >> > >>>>>> >> >> >> > > > > > > > > > >> >> > >>>>>> [1] >> >> >> > > > > > > > > > >> >> > >>>>>> >> >> >> > > > > > > > > > >> >> > >>>>>> >> >> >> > > > > > > > > > >> >> > >>>>> >> >> >> > > > > > > > > > >> >> > >>>> >> >> >> > > > > > > > > > >> >> > >>> >> >> >> > > > > > > > > > >> >> > >> >> >> >> > > > > > > > > > >> >> > >> >> >> > > > > > > > > > >> >> >> >> >> > > > > > > > > > >> >> >> >> > > > > > > > > > >> >> >> > > > > > > > > >> >> >> > > > > > > > >> >> >> > > > > > > >> >> >> > > > > > >> >> >> > > > > >> >> >> > > > >> >> >> > > >> >> >> > >> >> >> >> >> >> https://spotify.github.io/completable-futures/apidocs/com/spotify/futures/ConcurrencyReducer.html >> >> >> > > > > > > > > > >> >> > >>>>>> [2] >> >> >> > > > > > > > > > >> >> > >>>>>> >> >> >> > > > > > > > > > >> >> > >>>>>> >> >> >> > > > > > > > > > >> >> > >>>>> >> >> >> > > > > > > > > > >> >> > >>>> >> >> >> > > > > > > > > > >> >> > >>> >> >> >> > > > > > > > > > >> >> > >> >> >> >> > > > > > > > > > >> >> > >> >> >> > > > > > > > > > >> >> >> >> >> > > > > > > > > > >> >> >> >> > > > > > > > > > >> >> >> > > > > > > > > >> >> >> > > > > > > > >> >> >> > > > > > > >> >> >> > > > > > >> >> >> > > > > >> >> >> > > > >> >> >> > > >> >> >> > >> >> >> >> >> >> https://lettuce.io/lettuce-4/release/api/com/lambdaworks/redis/RedisFuture.html >> >> >> > > > > > > > > > >> >> > >>>>>> [3] >> >> >> > > > > > > > > > >> >> > >>>>>> >> >> >> > > > > > > > > > >> >> > >>>>>> >> >> >> > > > > > > > > > >> >> > >>>>> >> >> >> > > > > > > > > > >> >> > >>>> >> >> >> > > > > > > > > > >> >> > >>> >> >> >> > > > > > > > > > >> >> > >> >> >> >> > > > > > > > > > >> >> > >> >> >> > > > > > > > > > >> >> >> >> >> > > > > > > > > > >> >> >> >> > > > > > > > > > >> >> >> > > > > > > > > >> >> >> > > > > > > > >> >> >> > > > > > > >> >> >> > > > > > >> >> >> > > > > >> >> >> > > > >> >> >> > > >> >> >> > >> >> >> >> >> >> https://javadoc.io/static/org.jspare.vertx/vertx-jspare/1.1.0-M03/org/jspare/vertx/concurrent/VertxCompletableFuture.html >> >> >> > > > > > > > > > >> >> > >>>>>> -- >> >> >> > > > > > > > > > >> >> > >>>>>> Best regards, >> >> >> > > > > > > > > > >> >> > >>>>>> Andrey V. Mashenkov >> >> >> > > > > > > > > > >> >> > >>>>>> >> >> >> > > > > > > > > > >> >> > >>>>> >> >> >> > > > > > > > > > >> >> > >>>> >> >> >> > > > > > > > > > >> >> > >>>> >> >> >> > > > > > > > > > >> >> > >>>> -- >> >> >> > > > > > > > > > >> >> > >>>> >> >> >> > > > > > > > > > >> >> > >>>> Best regards, >> >> >> > > > > > > > > > >> >> > >>>> Alexei Scherbakov >> >> >> > > > > > > > > > >> >> > >>>> >> >> >> > > > > > > > > > >> >> > >>> >> >> >> > > > > > > > > > >> >> > >> >> >> >> > > > > > > > > > >> >> > >> >> >> >> > > > > > > > > > >> >> > >> -- >> >> >> > > > > > > > > > >> >> > >> Best regards, >> >> >> > > > > > > > > > >> >> > >> Alexey >> >> >> > > > > > > > > > >> >> > >> >> >> >> > > > > > > > > > >> >> > >> >> >> > > > > > > > > > >> >> > >> >> >> > > > > > > > > > >> >> >> >> >> > > > > > > > > > >> >> -- >> >> >> > > > > > > > > > >> >> Best regards, >> >> >> > > > > > > > > > >> >> Andrey V. Mashenkov >> >> >> > > > > > > > > > >> >> >> >> >> > > > > > > > > > >> > >> >> >> > > > > > > > > > >> >> >> >> > > > > > > > > > >> >> >> >> > > > > > > > > > >> -- >> >> >> > > > > > > > > > >> >> >> >> > > > > > > > > > >> Best regards, >> >> >> > > > > > > > > > >> Ivan Pavlukhin >> >> >> > > > > > > > > > >> >> >> >> > > > > > > > > > > >> >> >> > > > > > > > > > >> >> >> > > > > > > > > > >> >> >> > > > > > > > > > -- >> >> >> > > > > > > > > > >> >> >> > > > > > > > > > Best regards, >> >> >> > > > > > > > > > Ivan Pavlukhin >> >> >> > > > > > > > > > >> >> >> > > > > > > > > >> >> >> > > > > > > > >> >> >> > > > > > > > >> >> >> > > > > > > > -- >> >> >> > > > > > > > Best regards, >> >> >> > > > > > > > Andrey V. Mashenkov >> >> >> > > > > > > > >> >> >> > > > > > > >> >> >> > > > > > -- >> >> >> > > > > > Regards, >> >> >> > > > > > >> >> >> > > > > > Atri >> >> >> > > > > > Apache Concerted >> >> >> > > > > > >> >> >> > > > > >> >> >> > > > >> >> >> > > >> >> >> > >> >> >> >> >> >> >> >> >> -- >> >> >> Best regards, >> >> >> Andrey V. Mashenkov >> >> >> >> >> > >> >> >> >> >> >> -- >> >> >> >> Best regards, >> >> Ivan Pavlukhin >> >> >> >> >> > >> > -- >> > Best regards, >> > Andrey V. Mashenkov >> > >> >> >> -- >> >> Best regards, >> Ivan Pavlukhin >> >> > > -- > Best regards, > Andrey V. Mashenkov > -- Best regards, Ivan Pavlukhin