Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Actions not executed for cancelled futures #2010

Closed
ummels opened this issue Jun 8, 2017 · 6 comments
Closed

Actions not executed for cancelled futures #2010

ummels opened this issue Jun 8, 2017 · 6 comments

Comments

@ummels
Copy link
Contributor

ummels commented Jun 8, 2017

According to the documentation, actions registered with onFailure should be executed when a future is cancelled. However, this does not seem to be the case as the following code prints nothing:

Future<?> f = Future.of(() -> { while (true) {} });
f.onFailure(e -> println("Failure"));
f.cancel();
if (!f.isFailure())
    println("Oops");
Thread.sleep(1000L);
System.exit(0);
@nfekete
Copy link
Member

nfekete commented Jun 8, 2017

Note that while this doesn't affect the bug itself, while (true) {} is not interruptible, i.e., it will never release the thread back to the ExecutorService, even if you call cancel().

@ummels
Copy link
Contributor Author

ummels commented Jun 9, 2017

Thanks for the info. I guess while (true) { Thread.sleep(100L); } would be a better example.

@ruslansennov
Copy link
Member

It seems that the problem code is FutureImpl.java#L199. Computation fails in Try block with InterruptedException which is fatal according to Try.java#L1493.

I believe we should use classic try {} catch () {} block here.
See #1976

@ruslansennov
Copy link
Member

And maybe actions.forEach(this::perform) should be here

@ruslansennov
Copy link
Member

see #1963

@danieldietrich
Copy link
Contributor

danieldietrich commented Jul 16, 2017

I think the FutureImpl.cancel(boolean) function needs to look like this:

    @Override
    public boolean cancel(boolean mayInterruptIfRunning) {
        synchronized (lock) {
            if (isCompleted()) {
                return false;
            } else {
                return Try.of(() -> job == null || job.cancel(mayInterruptIfRunning)).onSuccess(cancelled -> {
                    if (cancelled) {
                        complete(Try.failure(new CancellationException()));
                    }
                }).getOrElse(false);
            }
        }
    }

Interestingly we already have a unit test:

    @SuppressWarnings("InfiniteLoopStatement")
    @Test
    public void shouldInterruptLockedFuture() {
        final Future<?> future = Future.of(() -> {
            while (true) {
                Try.run(() -> Thread.sleep(100));
            }
        });
        future.onComplete(r -> fail("future should lock forever"));
        future.cancel();
        assertCancelled(future);
    }

After the fix is applied, the onComplete handler, which throws an AssertionError, is executed. Currently the onComplete actions are executed on different threads (which will be changed with #1530), so the unit test is still green.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants