From a87afd222afa3505216af0741be34357588cb640 Mon Sep 17 00:00:00 2001 From: Julien Viet Date: Tue, 5 Nov 2024 09:20:22 +0100 Subject: [PATCH] Future.await should interrupt the current thread when the worker executor is closed. Motivation: Future.await incorrectly performs a no-op when the worker executor is closed (returns a null latch), which reports a failure that might not exist. Changes: When the worker executor returns null, throw an interrupted exception. --- src/main/java/io/vertx/core/Future.java | 5 +++- .../vertx/core/VirtualThreadContextTest.java | 27 +++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/src/main/java/io/vertx/core/Future.java b/src/main/java/io/vertx/core/Future.java index 575d14efe00..824026ab536 100644 --- a/src/main/java/io/vertx/core/Future.java +++ b/src/main/java/io/vertx/core/Future.java @@ -683,9 +683,12 @@ static T await(Future future) { } if (future.succeeded()) { return future.result(); - } else { + } else if (future.failed()) { Utils.throwAsUnchecked(future.cause()); return null; + } else { + Utils.throwAsUnchecked(new InterruptedException("Context closed")); + return null; } } diff --git a/src/test/java/io/vertx/core/VirtualThreadContextTest.java b/src/test/java/io/vertx/core/VirtualThreadContextTest.java index b8bed95272c..21739711756 100644 --- a/src/test/java/io/vertx/core/VirtualThreadContextTest.java +++ b/src/test/java/io/vertx/core/VirtualThreadContextTest.java @@ -349,4 +349,31 @@ public void testContextCloseContextSerialization() throws Exception { } f.toCompletionStage().toCompletableFuture().get(20, TimeUnit.SECONDS); } + + @Test + public void testAwaitWhenClosed() throws Exception { + Assume.assumeTrue(isVirtualThreadAvailable()); + ContextInternal ctx = vertx.createVirtualThreadContext(); + CountDownLatch latch = new CountDownLatch(1); + ctx.runOnContext(v -> { + latch.countDown(); + try { + new CountDownLatch(1).await(); + fail(); + } catch (InterruptedException expected) { + assertFalse(Thread.currentThread().isInterrupted()); + } + try { + Promise.promise().future().await(); + fail(); + } catch (Exception e) { + assertEquals(InterruptedException.class, e.getClass()); + testComplete(); + } + }); + awaitLatch(latch); + // Interrupts virtual thread + ctx.close(); + await(); + } }