Last active
November 22, 2021 20:48
-
-
Save paul-bjorkstrand/43bb8335453aa1eccb982b54556d7633 to your computer and use it in GitHub Desktop.
Loom snippets
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Roguh translation for my first approach, that had no way to an | |
// underlying error that occurred during execution of the tasks | |
class test { | |
public <V> List<V> test(List<Callable<V>> someTasks) { | |
try (var se = StructuredExecutor.open()) { | |
var futures = someTasks.stream() | |
.map(se::fork); | |
se.join(); | |
return futures.map(Future::resultNow) | |
.toList(); | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// My first attempt at solving the visibility problem for the exception | |
// see cleanSnippet.java for the simple example | |
class test { | |
public <V> List<V> test(List<Callable<V>> someTasks) { | |
try (var se = StructuredExecutor.open()) { | |
var futures = someTasks.stream() | |
.map(se::fork) | |
.toList(); | |
se.join(); | |
futures.stream() | |
.filter(f -> f.state() == Future.State.FAILED) | |
.findAny() | |
.ifPresent(f -> throw new RuntimeException(f.exceptionNow())); | |
return futures.stream() | |
.map(Future::resultNow) | |
.toList(); | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// After Brian's email explaining more on .resultNow(), an example on how to solve the problem | |
// in a canonical manner | |
public final class TrackFirstFailure implements BiConsumer<StructuredExecutor, Future<Object>> { | |
// ... similar state as ShutdownOnFailure ... | |
public void accept(StructuredExecutor executor, Future<Object> future) { | |
// ... same code as ShutdownOnFailure.accept, but without the call to executor.shutdown() | |
} | |
// ... exact same remaining impl as ShutdownOnFailure ... | |
} | |
class test { | |
public <V> List<V> test(List<Callable<V>> someTasks) { | |
try (var se = StructuredExecutor.open()) { | |
var trackingPolicy = new TrackFirstFailure(); | |
var futures = someTasks.stream() | |
.map(task -> se.fork(task, trackingPolicy); | |
se.join(); | |
trackingPolicy.throwIfFailed(); | |
return futures.map(Future::resultNow) | |
.toList(); | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// A further example, where StructuredExecutor has a built-in handler to track the first-failed task | |
// This impl can be built into StructuredExecutor, or an instance can be exposed by StructuredExecutor | |
public final class TrackFirstFailure implements BiConsumer<StructuredExecutor, Future<Object>> { | |
// ... similar state as ShutdownOnFailure ... | |
public void accept(StructuredExecutor executor, Future<Object> future) { | |
// ... same code as ShutdownOnFailure.accept, but without the call to executor.shutdown() | |
} | |
// ... exact same remaining impl as ShutdownOnFailure ... | |
} | |
class test { | |
public <V> List<V> test(List<Callable<V>> someTasks) { | |
try (var se = StructuredExecutor.open()) { | |
var futures = someTasks.stream() | |
.map(se::fork); | |
se.join(); | |
se.throwIfFailed(); | |
// Or, se.handler().throwIfFailed(); | |
return futures.map(Future::resultNow) | |
.toList(); | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// A further example, with overload(s) for StructuredExecutor.open() | |
public final class TrackFirstFailure implements BiConsumer<StructuredExecutor, Future<Object>> { | |
// ... similar state as ShutdownOnFailure ... | |
public void accept(StructuredExecutor executor, Future<Object> future) { | |
// ... same code as ShutdownOnFailure.accept, but without the call to executor.shutdown() | |
} | |
// ... exact same remaining impl as ShutdownOnFailure ... | |
} | |
class test { | |
public <V> List<V> test(List<Callable<V>> someTasks) { | |
var trackingPolicy = new TrackFirstFailure(); | |
// This handler is used as a default when no handler is provided to .fork() | |
// This will likely add additional complexity that may prove unnecessary, | |
// but it may be useful for simple code | |
try (var se = StructuredExecutor.open(trackingPolicy)) { | |
var futures = someTasks.stream() | |
.map(se::fork); // no need to add the handler here | |
se.join(); | |
trackingPolicy.throwIfFailed(); | |
return futures.map(Future::resultNow) | |
.toList(); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
cleanExample.java shows a naive understanding of StructuredExecutors.
lessCleanExample.java shows a clunky way to resolve it, due to a lack of understanding in how the "handlers" are used.
newHandlerEcample.java shows, perhaps, the simplest way to approach the situation. It would be nice if this handler were at least part of the first preview release, and would cover many use cases where the exception is only needed for bubbling up and/or logging.
newHandlerWithOverload.java is a more complicated way, but allows developers to define a "default" handler, when none is specified in the
.fork()
calls.newHandlerPartOfTheExecutor.java builds the "tracking" handler into
StructuredExecutor
itself.