|
11 | 11 | import java.util.function.Consumer;
|
12 | 12 | import java.util.function.Function;
|
13 | 13 |
|
| 14 | +import org.jboss.as.protocol.logging.ProtocolLogger; |
14 | 15 | import org.jboss.threads.AsyncFuture;
|
15 | 16 |
|
16 | 17 | /**
|
@@ -116,34 +117,39 @@ public boolean cancel(boolean mayInterruptIfRunning) {
|
116 | 117 | asyncCancelConsumer.accept(mayInterruptIfRunning);
|
117 | 118 | boolean afCancelled = asyncFuture.awaitUninterruptibly() == AsyncFuture.Status.CANCELLED;
|
118 | 119 |
|
119 |
| - if (!afCancelled) { |
| 120 | + if (afCancelled) { |
| 121 | + ProtocolLogger.ROOT_LOGGER.tracef("%s: AsyncFuture is cancelled; proceeding to cancel ourself", |
| 122 | + getClass().getEnclosingClass().getSimpleName(), getClass().getSimpleName()); |
| 123 | + } else { |
120 | 124 | // Our AsyncFuture.Listener completes this future asynchronously,
|
121 | 125 | // so block until it has done so before providing the resulting
|
122 | 126 | // state by calling super.cancel.
|
123 | 127 | //
|
124 | 128 | // We do this because canceling the async future may result in
|
125 |
| - // the canceled management op returning with either outcome=cancelled |
126 |
| - // or outcome=failed. We're in this block, so we know it's the latter. |
| 129 | + // the canceled management op returning with outcome=success, |
| 130 | + // outcome=failed or outcome=cancelled. |
127 | 131 | // We know this will result in the listener, in another
|
128 |
| - // thread, eventually trying to complete this exceptionally. |
| 132 | + // thread, eventually trying to complete or cancel this CompletableFuture. |
129 | 133 | // We don't want the determination of whether this method returns
|
130 | 134 | // true or false to be decided by a race between our call below to
|
131 |
| - // super.cancel and the listener thread completing the |
132 |
| - // future as failed. So we block to let the listener thread win the race. |
| 135 | + // super.cancel and the listener thread completing or cancelling the |
| 136 | + // future. So we block to let the listener thread win the race. |
133 | 137 | //
|
134 | 138 | // An alternative approach would be to call super.cancel first before
|
135 | 139 | // cancelling the asyncFuture. But that could result in inconsistency
|
136 | 140 | // between what this future reports vs the 'outcome' value of the
|
137 | 141 | // executed op. When ModelControllerClient async methods formerly returned an
|
138 | 142 | // AsyncFuture these results were consistent, so we're maintaining
|
139 | 143 | // that behavior with the CompletableFuture we now return.
|
| 144 | + ProtocolLogger.ROOT_LOGGER.tracef("%s.%s: Awaiting AsyncFuture.Listener before proceeding to cancel ourself", |
| 145 | + getClass().getEnclosingClass().getSimpleName(), getClass().getSimpleName()); |
140 | 146 | awaitLatch();
|
141 | 147 | }
|
142 | 148 | return super.cancel(mayInterruptIfRunning);
|
143 | 149 | } finally {
|
144 | 150 | // Code hardening:
|
145 | 151 | // If for some reason asyncFuture.awaitUninterruptibly() returns CANCELLED
|
146 |
| - // without the listener getting invoked, now that we're cancelled make sure |
| 152 | + // without the listener getting invoked (yet), now that we're cancelled make sure |
147 | 153 | // the latch is counted down so other calls to cancel don't block.
|
148 | 154 | latch.countDown();
|
149 | 155 | }
|
|
0 commit comments