New candidate JEP: 462: Structured Concurrency (Second Preview)
Sam Pullara
spullara at gmail.com
Fri Oct 27 21:23:29 UTC 2023
I have seen use cases for this when you are trying to remove tail latencies
from distributed systems. The idea is that you make a call and then wait
till some amount of time to make another call if the first hasn't completed
yet. Then return whichever one completes first and cancel the other (or
others). They are often called Backup Requests:
Jeff Dean's talk about rapid response times - Misc - Discuss Dgraph
<https://discuss.dgraph.io/t/jeff-deans-talk-about-rapid-response-times/83>
On Fri, Oct 27, 2023 at 1:41 PM Josiah Noel <josiahnoel at gmail.com> wrote:
> Author intent is one thing I suppose, but for new JDK APIs, I'm usually
> focused on how useful a particular feature is to me. Thus, I tried all the
> scenarios I could think of to make ShutdownOnSuccess work for me. It
> functions as advertised, but I simply can't find any use case for it in my
> projects. (perhaps I just lack imagination?) I find myself exclusively
> using ShutdownOnFailure or extending STS myself.
>
> On Fri, Oct 27, 2023 at 3:51 PM Eric Kolotyluk <eric at kolotyluk.net> wrote:
>
>> I have tried things out over the evolution of Structured Concurrency, but
>> not this specific case.
>>
>> While I agree that trying things out is a *good *way to see how it
>> works, trying things out does not confirm actual architectural or design
>> intent, it merely speculates on intent. It would be nice for the architects
>> to explicitly specify their intent in JEPs and elsewhere.
>>
>> But, thanks for the example... did you write it yourself, or have GitHub
>> Copilot do it? 😉 Just teasing...
>> On 2023-10-27 10:16 a.m., Josiah Noel wrote:
>>
>> Have you tried it out? Trying this stuff out is the best way to see how
>> it works, in any case, observe the following example
>>
>> try (ShutdownOnSuccess<Integer> scope = new StructuredTaskScope.
>> ShutdownOnSuccess<>()) {
>>
>> var fail =
>>
>> scope.fork(
>>
>> () -> {
>>
>> throw new IllegalAccessException();
>>
>> });
>>
>> scope.fork(
>>
>> () -> {
>>
>> Thread.sleep(Duration.of(random.nextInt(0, 1000), ChronoUnit.MILLIS));
>>
>> return 1;
>>
>> });
>>
>> scope.fork(
>>
>> () -> {
>>
>> Thread.sleep(Duration.of(random.nextInt(0, 1000), ChronoUnit.MILLIS));
>>
>> return 2;
>>
>> });
>>
>> scope.join();
>>
>> // get first result, (will not care about exceptions as long as one
>> succeeds)
>>
>> scope.result();
>>
>> // will throw an exception
>>
>> fail.get();
>>
>> }
>>
>>
>> Essentially, you must use the `scope.result()` method to retrieve the
>> result instead of calling the get methods on a particular subtask
>>
>> On Fri, Oct 27, 2023 at 12:37 PM Eric Kolotyluk <eric at kolotyluk.net>
>> wrote:
>>
>>> Looks good... thanks.
>>>
>>> One slight area of confusion for me was,
>>>
>>> <T> List<Future<T>> executeAll(List<Callable<T>> tasks)
>>> throws InterruptedException {
>>> try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
>>> List<? extends Supplier<Future<T>>> futures = tasks.stream()
>>> .map(task -> asFuture(task))
>>> .map(scope::fork)
>>> .toList();
>>> scope.join();
>>> return futures.stream().map(Supplier::get).toList();
>>> }
>>> }
>>>
>>> static <T> Callable<Future<T>> asFuture(Callable<T> task) {
>>> return () -> {
>>> try {
>>> return CompletableFuture.completedFuture(task.call());
>>> } catch (Exception ex) {
>>> return CompletableFuture.failedFuture(ex);
>>> }
>>> };
>>> }
>>>
>>> And what happens if ShutdownOnSuccess is called instead. Eventually I
>>> reasoned that the right thing should happen, but there should only ever be
>>> one element in the list. Does the scope guarantee only one result?
>>>
>>> 1. It would be slightly helpful to point this out in a note so that
>>> it is more obvious.
>>> 2. What is less obvious is that with ShutdownOnSuccess what happens
>>> if one or more of the siblings throw an exception?
>>> - I would hope that so long at least one task succeeds, this
>>> should not cause the overall success of the scope to fail.
>>> - It would be nice to see this explained more clearly.
>>> - Maybe ShutdownOnSuccess deserves its own example, discussing
>>> possible edge cases.
>>>
>>> Somehow I am remembering Scala 'for comprehensions' with concurrent
>>> tasks that 'yield' a result... 😉
>>>
>>> The current situation seems kinda clunky with using one stream to
>>> collect futures, and yet another stream to collect results. Maybe one of
>>> the Java architects hates such boilerplate, and will come up with an
>>> elegant way to reduce/remove such boilerplate.
>>>
>>> Sincerely, Eric
>>> On 2023-10-27 7:39 a.m., Mark Reinhold wrote:
>>>
>>> https://openjdk.org/jeps/462
>>>
>>> Summary: Simplify concurrent programming by introducing an API for
>>> structured concurrency. Structured concurrency treats groups of related
>>> tasks running in different threads as a single unit of work, thereby
>>> streamlining error handling and cancellation, improving reliability,
>>> and enhancing observability. This is a preview API.
>>>
>>> - Mark
>>>
>>>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/loom-dev/attachments/20231027/396586ca/attachment.htm>
More information about the loom-dev
mailing list