Description
Ivan Sopov opened SPR-17336 and commented
org.springframework.messaging.support.MonoToListenableFutureAdapter.cancel method is strange.
Consider adapter for the case that cannot be cancelled.
Future<Void> foo = new MonoToListenableFutureAdapter<>(Mono.empty());
System.out.println(foo.cancel(true));
System.out.println(foo.isCancelled());
This prints:
true
false
This clearly violates cancel method javadoc "Subsequent calls to isCancelled will always return true if this method returned true" And I believe cancel should've returned false itself since it should "return false if the task could not be cancelled, typically because it has already completed normally"
Also curent implementation gives result true several times under race if actual cancellation is happening. Consider the following JCStress-based test:
@JCStressTest
@Outcome(id = "true, false", expect = Expect.ACCEPTABLE)
@Outcome(id = "false, true", expect = Expect.ACCEPTABLE)
@Outcome(expect = Expect.FORBIDDEN, desc = "Other cases are forbidden.")
@State
public class MonoToListenableFutureAdapterCancelTest {
private final Future<Void> future = new MonoToListenableFutureAdapter<>(Mono.fromFuture(new CompletableFuture<>()));
@Actor
public void cancel1(ZZ_Result r) {
r.r1 = future.cancel(true);
}
@Actor
public void cancel2(ZZ_Result r) {
r.r2 = future.cancel(true);
}
}
It fails with "true, true" result while result "false, true" and "true, false" are also observed.
Affects: 5.1 GA
Issue Links:
- Support use of reactive clients in @MessageMapping methods [SPR-16634] #21175 Support use of reactive clients in
@MessageMapping
methods - DelegatingCompletableFuture.cancel() returns false for already cancelled future [SPR-17337] #21871 DelegatingCompletableFuture.cancel() returns false for already cancelled future