Skip to content

Commit

Permalink
Wait for thread completion only if interrupted flag set (#1843)
Browse files Browse the repository at this point in the history
* 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 <santiago.pericasgeertsen@oracle.com>

* 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 <santiago.pericasgeertsen@oracle.com>

* Updated copyright header.

Signed-off-by: Santiago Pericasgeertsen <santiago.pericasgeertsen@oracle.com>
  • Loading branch information
spericas committed May 21, 2020
1 parent c856b44 commit 1da6b23
Show file tree
Hide file tree
Showing 3 changed files with 79 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -450,17 +450,17 @@ private void logCircuitBreakerState(String preamble) {

/**
* <p>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.</p>
*
* <p>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}.</p>
* TimeoutUninterruptableTest::testTimeout}.</p>
*/
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) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*
* 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.
* 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";
}
}
Original file line number Diff line number Diff line change
@@ -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.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -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;

/**
Expand All @@ -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
Expand All @@ -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)));
}
}
}

0 comments on commit 1da6b23

Please sign in to comment.