Tugalsan Karabacak
Tugalsan Karabacak

Reputation: 643

scope.joinUtil is not working for nested StructuredTaskScope.ShutdownOnFailure

On Windows 11, Java 22, preview enabled, I am trying to use (JEP 453)'s joinUntil functionality to limit execution duration.

However, I am not able to use it in a nested way. The execution is not stopping even though I used scope.joinUntil.

Could you help me figure it out what is wrong with the code? I don't want to use it only in my main function, but also in my sub projects.

Project code: github

public class Main {

    public static void main(String... s) {
        nestedTest_pureJava(
            Duration.ofSeconds(8),
            Duration.ofSeconds(5),
            5
        );
    }

    private static void nestedTest_pureJava(Duration untilTimeout, Duration workLoad, int nestedId) {
        if (nestedId < 0) {
            out.println("nestedTest_pureJava -> skip -> " + nestedId);
            return;
        }
        out.println("nestedTest_pureJava -> begin -> " + nestedId);
        try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
            scope.fork(() -> {
                Thread.sleep(workLoad);
                return null;
            });
            scope.joinUntil(Instant.now().plusSeconds(untilTimeout.getSeconds()));
            scope.throwIfFailed();
            nestedTest_pureJava(untilTimeout, workLoad, nestedId - 1);
        } catch (InterruptedException | TimeoutException | ExecutionException e) {
            throw new RuntimeException(e);
        }
        out.println("nestedTest_pureJava -> end -> " + nestedId);
    }
    
}

Output:

nestedTest_pureJava -> begin -> 5
nestedTest_pureJava -> begin -> 4
nestedTest_pureJava -> begin -> 3
nestedTest_pureJava -> begin -> 2
nestedTest_pureJava -> begin -> 1
nestedTest_pureJava -> begin -> 0
nestedTest_pureJava -> skip -> -1
nestedTest_pureJava -> end -> 0
nestedTest_pureJava -> end -> 1
nestedTest_pureJava -> end -> 2
nestedTest_pureJava -> end -> 3
nestedTest_pureJava -> end -> 4
nestedTest_pureJava -> end -> 5

As I am catching the TimeoutException, I have tried to shutdown the scope, but the problem still persists.

private static void nestedTest_pureJava(Duration untilTimeout, Duration workLoad, int nestedId) {
    if (nestedId < 0) {
        out.println("nestedTest_pureJava -> skip -> " + nestedId);
        return;
    }
    out.println("nestedTest_pureJava -> begin -> " + nestedId);
    var scope = new StructuredTaskScope.ShutdownOnFailure();
    try {
        scope.fork(() -> {
            Thread.sleep(workLoad);
            return null;
        });
        scope.joinUntil(Instant.now().plusSeconds(untilTimeout.getSeconds()));
        scope.throwIfFailed();
        nestedTest_pureJava(untilTimeout, workLoad, nestedId - 1);
    } catch (InterruptedException | TimeoutException | ExecutionException e) {
        if (e instanceof TimeoutException) {
            scope.shutdown();
        }
        throw new RuntimeException(e);
    } finally {
        scope.close();
    }
    out.println("nestedTest_pureJava -> end -> " + nestedId);
}

Upvotes: 1

Views: 134

Answers (1)

Tugalsan Karabacak
Tugalsan Karabacak

Reputation: 643

As Holger already answered the recursive-code should be inside 'scope.fork(...)'

public class Main {

    public static void main(String... s) {
        nestedTest_pureJava(
            Duration.ofSeconds(8),
            Duration.ofSeconds(5),
            5
        );
    }

    private static void nestedTest_pureJava(Duration untilTimeout, Duration workLoad, int nestedId) {
        if (nestedId < 0) {
            out.println("nestedTest_pureJava -> skip -> " + nestedId);
            return;
        }
        out.println("nestedTest_pureJava -> begin -> " + nestedId);
        var scope = new StructuredTaskScope.ShutdownOnFailure();
        try {
            scope.fork(() -> {
                Thread.sleep(workLoad);
                nestedTest_pureJava(untilTimeout, workLoad, nestedId - 1);
                return null;
            });
            scope.joinUntil(Instant.now().plusSeconds(untilTimeout.getSeconds()));
            scope.throwIfFailed();

        } catch (InterruptedException | TimeoutException | ExecutionException e) {
            if (e instanceof InterruptedException) {
                Thread.currentThread().interrupt();
            }
            if (e instanceof TimeoutException) {
                scope.shutdown();
            }
            throw new RuntimeException(e);
        } finally {
            scope.close();
        }
        out.println("nestedTest_pureJava -> end -> " + nestedId);
    }
}

Upvotes: 1

Related Questions