From 40a074d729d026b76e10c209a28a487644949e4e Mon Sep 17 00:00:00 2001 From: Santiago Pericasgeertsen Date: Wed, 20 May 2020 15:27:11 -0400 Subject: [PATCH 1/3] Wait for a thread to complete only if its interrupted flag has been set and it is still running. Some new tests. Signed-off-by: Santiago Pericasgeertsen --- .../faulttolerance/FaultToleranceCommand.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/microprofile/fault-tolerance/src/main/java/io/helidon/microprofile/faulttolerance/FaultToleranceCommand.java b/microprofile/fault-tolerance/src/main/java/io/helidon/microprofile/faulttolerance/FaultToleranceCommand.java index 56d716c3f16..05465b33d58 100644 --- a/microprofile/fault-tolerance/src/main/java/io/helidon/microprofile/faulttolerance/FaultToleranceCommand.java +++ b/microprofile/fault-tolerance/src/main/java/io/helidon/microprofile/faulttolerance/FaultToleranceCommand.java @@ -450,17 +450,17 @@ private void logCircuitBreakerState(String preamble) { /** *

After a timeout expires, Hystrix can report an {@link ExecutionException} - * while a thread is still running and cannot be interrupted (e.g. busy - * loop). Hystrix makes this possible by using another thread to monitor + * when a thread has been interrupted but it is still running (e.g. while in a + * busy loop). Hystrix makes this possible by using another thread to monitor * the command's thread.

* *

According to the FT spec, the thread may continue to run, so here * we give it a chance to do that before completing the execution of the * command. For more information see TCK test {@code - * TimeoutUninterruptableTest::timeoutTest}.

+ * TimeoutUninterruptableTest::testTimeout}.

*/ private void waitForThreadToComplete() { - if (!introspector.isAsynchronous() && runThread != null) { + if (!introspector.isAsynchronous() && runThread != null && runThread.isInterrupted()) { try { int waitTime = 250; while (runThread.getState() == Thread.State.RUNNABLE && waitTime <= threadWaitingPeriod) { From 0b2c7cd72ff38f80fab14359108e4bdfd981c3f9 Mon Sep 17 00:00:00 2001 From: Santiago Pericasgeertsen Date: Wed, 20 May 2020 15:27:11 -0400 Subject: [PATCH 2/3] Wait for a thread to complete only if its interrupted flag has been set and it is still running. Some new tests. Signed-off-by: Santiago Pericasgeertsen --- .../faulttolerance/TimeoutNoRetryBean.java | 47 +++++++++++++++++++ .../faulttolerance/TimeoutTest.java | 33 +++++++++++-- 2 files changed, 75 insertions(+), 5 deletions(-) create mode 100644 microprofile/fault-tolerance/src/test/java/io/helidon/microprofile/faulttolerance/TimeoutNoRetryBean.java diff --git a/microprofile/fault-tolerance/src/test/java/io/helidon/microprofile/faulttolerance/TimeoutNoRetryBean.java b/microprofile/fault-tolerance/src/test/java/io/helidon/microprofile/faulttolerance/TimeoutNoRetryBean.java new file mode 100644 index 00000000000..a671e7c4c36 --- /dev/null +++ b/microprofile/fault-tolerance/src/test/java/io/helidon/microprofile/faulttolerance/TimeoutNoRetryBean.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2020 Oracle and/or its affiliates. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.helidon.microprofile.faulttolerance; + +import java.time.temporal.ChronoUnit; +import javax.enterprise.context.Dependent; + +import org.eclipse.microprofile.faulttolerance.Timeout; +import org.eclipse.microprofile.faulttolerance.exceptions.TimeoutException; + +/** + * Class TimeoutNoRetryBean. + */ +@Dependent +public class TimeoutNoRetryBean { + + @Timeout(value=1000, unit=ChronoUnit.MILLIS) + public String forceTimeoutSleep() throws InterruptedException, TimeoutException { + FaultToleranceTest.printStatus("TimeoutNoRetryBean::forceTimeout()", "failure"); + Thread.sleep(2000); + return "failure"; + } + + @Timeout(value=1000, unit=ChronoUnit.MILLIS) + public String forceTimeoutLoop() throws TimeoutException { + FaultToleranceTest.printStatus("TimeoutNoRetryBean::forceTimeoutLoop()", "failure"); + long start = System.currentTimeMillis(); + while (System.currentTimeMillis() - start < 2000) { + // busy loop + } + return "success"; + } +} diff --git a/microprofile/fault-tolerance/src/test/java/io/helidon/microprofile/faulttolerance/TimeoutTest.java b/microprofile/fault-tolerance/src/test/java/io/helidon/microprofile/faulttolerance/TimeoutTest.java index ab584d78a45..ea1cf2eab8e 100644 --- a/microprofile/fault-tolerance/src/test/java/io/helidon/microprofile/faulttolerance/TimeoutTest.java +++ b/microprofile/fault-tolerance/src/test/java/io/helidon/microprofile/faulttolerance/TimeoutTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2019 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2020 Oracle and/or its affiliates. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,10 +17,13 @@ package io.helidon.microprofile.faulttolerance; import org.eclipse.microprofile.faulttolerance.exceptions.TimeoutException; + import org.junit.jupiter.api.Test; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.greaterThan; +import static org.hamcrest.Matchers.lessThan; import static org.junit.jupiter.api.Assertions.assertThrows; /** @@ -29,11 +32,9 @@ public class TimeoutTest extends FaultToleranceTest { @Test - public void testForceTimeout() throws Exception { + public void testForceTimeout() { TimeoutBean bean = newBean(TimeoutBean.class); - assertThrows(TimeoutException.class, () -> { - bean.forceTimeout(); - }); + assertThrows(TimeoutException.class, bean::forceTimeout); } @Test @@ -59,4 +60,26 @@ public void testTimeoutWithRetriesAndFallback() throws Exception { TimeoutBean bean = newBean(TimeoutBean.class); assertThat(bean.timeoutWithRetriesAndFallback(), is("fallback")); } + + @Test + public void testForceTimeoutSleep() { + TimeoutNoRetryBean bean = newBean(TimeoutNoRetryBean.class); + long start = System.currentTimeMillis(); + try { + bean.forceTimeoutSleep(); // can interrupt + } catch (InterruptedException | TimeoutException e) { + assertThat(System.currentTimeMillis() - start, is(lessThan(2000L))); + } + } + + @Test + public void testForceTimeoutLoop() { + TimeoutNoRetryBean bean = newBean(TimeoutNoRetryBean.class); + long start = System.currentTimeMillis(); + try { + bean.forceTimeoutLoop(); // cannot interrupt + } catch (TimeoutException e) { + assertThat(System.currentTimeMillis() - start, is(greaterThan(2000L))); + } + } } From 29ca7611e52c5b3ba1e841821758b0979c2ffac2 Mon Sep 17 00:00:00 2001 From: Santiago Pericasgeertsen Date: Thu, 21 May 2020 08:53:52 -0400 Subject: [PATCH 3/3] Updated copyright header. Signed-off-by: Santiago Pericasgeertsen --- .../helidon/microprofile/faulttolerance/TimeoutNoRetryBean.java | 2 +- .../io/helidon/microprofile/faulttolerance/TimeoutTest.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/microprofile/fault-tolerance/src/test/java/io/helidon/microprofile/faulttolerance/TimeoutNoRetryBean.java b/microprofile/fault-tolerance/src/test/java/io/helidon/microprofile/faulttolerance/TimeoutNoRetryBean.java index a671e7c4c36..ffbc03c9e0a 100644 --- a/microprofile/fault-tolerance/src/test/java/io/helidon/microprofile/faulttolerance/TimeoutNoRetryBean.java +++ b/microprofile/fault-tolerance/src/test/java/io/helidon/microprofile/faulttolerance/TimeoutNoRetryBean.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020 Oracle and/or its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/microprofile/fault-tolerance/src/test/java/io/helidon/microprofile/faulttolerance/TimeoutTest.java b/microprofile/fault-tolerance/src/test/java/io/helidon/microprofile/faulttolerance/TimeoutTest.java index ea1cf2eab8e..4d289c058eb 100644 --- a/microprofile/fault-tolerance/src/test/java/io/helidon/microprofile/faulttolerance/TimeoutTest.java +++ b/microprofile/fault-tolerance/src/test/java/io/helidon/microprofile/faulttolerance/TimeoutTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2020 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2020 Oracle and/or its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License.