Loom EA and using a custom Joiner

mikmoila mika.a.moilanen at gmail.com
Fri Nov 22 21:49:44 UTC 2024


Yes this is more or less what I already had; I need to return a Stream of TaskResults, including TestFailed - cases:

           return switch (subtask.state()) {
                case SUCCESS -> {
                    TaskResult taskResult = subtask.get();
                    results.add(taskResult); // collect all cases
                    yield !(taskResult instanceof Completed);
                }
                case FAILED -> {
                    firstException.compareAndSet(null, subtask.exception());
                    yield true;
                }
                case UNAVAILABLE -> true;
            };


> Alan Bateman <Alan.Bateman at oracle.com> kirjoitti 15.11.2024 kello 13.49:
> 
> 
> 
>> On 15/11/2024 07:47, Mika Moilanen wrote:
>> Hello,
>> 
>> I've been playing around with the latest EA (https://openjdk.org/jeps/8340343) build with Joiners et al.
>> I'm building a small utility which reads a list of http requests from a file and runs them concurrently. These tasks have an associated test which is an assertion about the http response.
>> Tasks can either succeed or they can fail in two ways:
>> 
>> 1) expected failure: test or its execution can fail
>> 2) something unexpected outside of the test execution e.g NPE happens.
>> 
>> Task are self-contained and TaskResponse contains all the data needed for reporting the outcome to the user:
>> 
>> sealed interface TaskResult {
>>   record Success(....) ...
>>   record TestFailed(... ) .. // test failed
>>   record Failure(...) ... // something else failed e.g an exception during the http call
>> }
>> 
>> In case of successfull SubTask I need to check if the TaskResult is TestFailed or Failure, and shutdown the scope preventing processing of tasks, and report about the outcome.
>> In case of any SubTask if failing I need only the exception from the last SubTask::exception().
>> 
>> I started with a StructuredTaskScope.Joiner.allUntil(<a predicate which examines TaskResult>) but noticed that join() doesn't throw, and thus proceeded in implementing a custom Joiner which stores the last exception and overrides result and onComplete - methods.
>> 
> 
> I think this is more about adaptation which can be done when forking or when the subtask completes, both will work.
> 
> At fork time it could be:
> 
>   Callable<T> adapt(Callable<TaskResult<T>> task) { .. }
> 
> and the default joiner or Joiner.awaitAllSuccessfulOrThrow will work as the onComplete will be called with a successful or failed subtask.
> 
> If you want join to return a TaskResult, or stream of, then it will require a custom Joiner that extracts the exception when a subtask succeeds with TaskFailed, the onComplete will look something like:
> 
>         @Override
>         public boolean onComplete(Subtask<? extends TaskResult<T>> subtask) {
>             if (subtask.state() == Subtask.State.SUCCESS) {
>                 return (subtask.get() instanceof TaskResult.TestFailed<T> failed)
>                         && FIRST_EXCEPTION.compareAndSet(this, null, failed.exception());
>             } else {
>                 return true;  // cancel unconditionally
>             }
>         }
> 
> which may be what you have already.
> 
> -Alan


More information about the loom-dev mailing list