mirror of https://github.com/apache/jclouds.git
Issue 501: break retry loop on timeout or illegal state
This commit is contained in:
parent
79a5edd1e2
commit
8ed7dcde82
|
@ -22,6 +22,7 @@ package org.jclouds.compute.strategy;
|
||||||
import static com.google.common.base.Preconditions.checkNotNull;
|
import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
import static com.google.common.base.Preconditions.checkState;
|
import static com.google.common.base.Preconditions.checkState;
|
||||||
import static com.google.common.base.Throwables.getRootCause;
|
import static com.google.common.base.Throwables.getRootCause;
|
||||||
|
import static java.lang.String.format;
|
||||||
import static org.jclouds.compute.util.ComputeServiceUtils.findReachableSocketOnNode;
|
import static org.jclouds.compute.util.ComputeServiceUtils.findReachableSocketOnNode;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
@ -126,6 +127,7 @@ public class CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap implements Cal
|
||||||
public Void call() {
|
public Void call() {
|
||||||
checkState(!tainted, "this object is not designed to be reused: %s", toString());
|
checkState(!tainted, "this object is not designed to be reused: %s", toString());
|
||||||
tainted = true;
|
tainted = true;
|
||||||
|
String originalId = node.getId();
|
||||||
try {
|
try {
|
||||||
if (options.shouldBlockUntilRunning()) {
|
if (options.shouldBlockUntilRunning()) {
|
||||||
if (nodeRunning.apply(node)) {
|
if (nodeRunning.apply(node)) {
|
||||||
|
@ -133,10 +135,12 @@ public class CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap implements Cal
|
||||||
} else {
|
} else {
|
||||||
NodeMetadata nodeForState = getNode.getNode(node.getId());
|
NodeMetadata nodeForState = getNode.getNode(node.getId());
|
||||||
NodeState state = nodeForState == null ? NodeState.TERMINATED : nodeForState.getState();
|
NodeState state = nodeForState == null ? NodeState.TERMINATED : nodeForState.getState();
|
||||||
throw new IllegalStateException(String.format(
|
throw new IllegalStateException(format(
|
||||||
"node didn't achieve the state running on node %s within %d seconds, final state: %s", node
|
"node %s didn't achieve the state running within %d seconds, final state: %s", originalId,
|
||||||
.getId(), timeouts.nodeRunning / 1000, state));
|
timeouts.nodeRunning / 1000, state));
|
||||||
}
|
}
|
||||||
|
if (node == null)
|
||||||
|
throw new IllegalStateException(format("node %s terminated before applying options", originalId));
|
||||||
if (statement != null) {
|
if (statement != null) {
|
||||||
RunScriptOnNode runner = initScriptRunnerFactory.create(node, statement, options, badNodes).call();
|
RunScriptOnNode runner = initScriptRunnerFactory.create(node, statement, options, badNodes).call();
|
||||||
if (runner != null) {
|
if (runner != null) {
|
||||||
|
@ -148,10 +152,10 @@ public class CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap implements Cal
|
||||||
findReachableSocketOnNode(socketTester.seconds(options.getSeconds()), node, options.getPort());
|
findReachableSocketOnNode(socketTester.seconds(options.getSeconds()), node, options.getPort());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
logger.debug("<< options applied node(%s)", node.getId());
|
logger.debug("<< options applied node(%s)", originalId);
|
||||||
goodNodes.add(node);
|
goodNodes.add(node);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
logger.error(e, "<< problem applying options to node(%s): ", node.getId(), getRootCause(e).getMessage());
|
logger.error(e, "<< problem applying options to node(%s): ", originalId, getRootCause(e).getMessage());
|
||||||
badNodes.put(node, e);
|
badNodes.put(node, e);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
|
|
|
@ -19,14 +19,16 @@
|
||||||
|
|
||||||
package org.jclouds.predicates;
|
package org.jclouds.predicates;
|
||||||
|
|
||||||
|
import static org.jclouds.util.Throwables2.getFirstThrowableOfType;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.concurrent.TimeoutException;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
|
|
||||||
import org.jclouds.logging.Logger;
|
import org.jclouds.logging.Logger;
|
||||||
import org.jclouds.util.Throwables2;
|
|
||||||
|
|
||||||
import com.google.common.base.Predicate;
|
import com.google.common.base.Predicate;
|
||||||
|
|
||||||
|
@ -75,10 +77,16 @@ public class RetryablePredicate<T> implements Predicate<T> {
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
logger.warn(e, "predicate %s on %s interrupted, returning false", input, predicate);
|
logger.warn(e, "predicate %s on %s interrupted, returning false", input, predicate);
|
||||||
} catch (RuntimeException e) {
|
} catch (RuntimeException e) {
|
||||||
ExecutionException exec = Throwables2.getFirstThrowableOfType(e, ExecutionException.class);
|
if (getFirstThrowableOfType(e, ExecutionException.class) != null) {
|
||||||
if (exec != null)
|
logger.warn(e, "predicate %s on %s errored [%s], returning false", input, predicate, e.getMessage());
|
||||||
logger.warn(exec, "predicate %s on %s error, returning false", input, predicate);
|
return false;
|
||||||
else
|
} else if (getFirstThrowableOfType(e, IllegalStateException.class) != null) {
|
||||||
|
logger.warn(e, "predicate %s on %s illegal state [%s], returning false", input, predicate, e.getMessage());
|
||||||
|
return false;
|
||||||
|
} else if (getFirstThrowableOfType(e, TimeoutException.class) != null) {
|
||||||
|
logger.warn(e, "predicate %s on %s timed out [%s], returning false", input, predicate, e.getMessage());
|
||||||
|
return false;
|
||||||
|
} else
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -20,12 +20,15 @@
|
||||||
package org.jclouds.predicates;
|
package org.jclouds.predicates;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
import java.util.concurrent.ExecutionException;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.concurrent.TimeoutException;
|
||||||
|
|
||||||
import org.testng.annotations.Test;
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
import com.google.common.base.Predicate;
|
import com.google.common.base.Predicate;
|
||||||
import com.google.common.base.Predicates;
|
import com.google.common.base.Predicates;
|
||||||
|
import com.google.common.base.Supplier;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
@ -36,6 +39,56 @@ import com.google.common.base.Predicates;
|
||||||
public class RetryablePredicateTest {
|
public class RetryablePredicateTest {
|
||||||
public static int SLOW_BUILD_SERVER_GRACE = 50;
|
public static int SLOW_BUILD_SERVER_GRACE = 50;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testFalseOnIllegalStateExeception() {
|
||||||
|
ensureImmediateReturnFor(new IllegalStateException());
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("serial")
|
||||||
|
@Test
|
||||||
|
void testFalseOnExecutionException() {
|
||||||
|
ensureImmediateReturnFor(new ExecutionException() {
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("serial")
|
||||||
|
@Test
|
||||||
|
void testFalseOnTimeoutException() {
|
||||||
|
ensureImmediateReturnFor(new TimeoutException() {
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("serial")
|
||||||
|
@Test(expectedExceptions = RuntimeException.class)
|
||||||
|
void testPropagateOnException() {
|
||||||
|
ensureImmediateReturnFor(new Exception() {
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ensureImmediateReturnFor(final Exception ex) {
|
||||||
|
RetryablePredicate<Supplier<String>> predicate = new RetryablePredicate<Supplier<String>>(
|
||||||
|
new Predicate<Supplier<String>>() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean apply(Supplier<String> input) {
|
||||||
|
return "goo".equals(input.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
}, 3, 1, TimeUnit.SECONDS);
|
||||||
|
Date startPlusThird = new Date(System.currentTimeMillis() + 1000);
|
||||||
|
assert !predicate.apply(new Supplier<String>() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String get() {
|
||||||
|
throw new RuntimeException(ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
Date now = new Date();
|
||||||
|
assert now.compareTo(startPlusThird) < 0 : String.format("%s should be less than %s", now.getTime(),
|
||||||
|
startPlusThird.getTime());
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testAlwaysTrue() {
|
void testAlwaysTrue() {
|
||||||
RetryablePredicate<String> predicate = new RetryablePredicate<String>(Predicates.<String> alwaysTrue(), 3, 1,
|
RetryablePredicate<String> predicate = new RetryablePredicate<String>(Predicates.<String> alwaysTrue(), 3, 1,
|
||||||
|
|
|
@ -20,7 +20,6 @@
|
||||||
package org.jclouds.aws.ec2.predicates;
|
package org.jclouds.aws.ec2.predicates;
|
||||||
|
|
||||||
import java.util.NoSuchElementException;
|
import java.util.NoSuchElementException;
|
||||||
import java.util.concurrent.ExecutionException;
|
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
import javax.inject.Singleton;
|
import javax.inject.Singleton;
|
||||||
|
@ -31,7 +30,6 @@ import org.jclouds.logging.Logger;
|
||||||
import org.jclouds.rest.ResourceNotFoundException;
|
import org.jclouds.rest.ResourceNotFoundException;
|
||||||
|
|
||||||
import com.google.common.base.Predicate;
|
import com.google.common.base.Predicate;
|
||||||
import com.google.common.base.Throwables;
|
|
||||||
import com.google.common.collect.Iterables;
|
import com.google.common.collect.Iterables;
|
||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
|
|
||||||
|
@ -58,16 +56,12 @@ public class SpotInstanceRequestActive implements Predicate<SpotInstanceRequest>
|
||||||
try {
|
try {
|
||||||
spot = refresh(spot);
|
spot = refresh(spot);
|
||||||
logger.trace("%s: looking for spot state %s: currently: %s", spot.getId(), SpotInstanceRequest.State.ACTIVE,
|
logger.trace("%s: looking for spot state %s: currently: %s", spot.getId(), SpotInstanceRequest.State.ACTIVE,
|
||||||
spot.getState());
|
spot.getState());
|
||||||
if (spot.getState() == SpotInstanceRequest.State.CANCELLED)
|
if (spot.getState() == SpotInstanceRequest.State.CANCELLED)
|
||||||
Throwables.propagate(new ExecutionException(String.format("spot request %s cancelled", spot.getId())) {
|
throw new IllegalStateException(String.format("spot request %s cancelled", spot.getId()));
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
});
|
|
||||||
if (spot.getFaultCode() != null)
|
if (spot.getFaultCode() != null)
|
||||||
Throwables.propagate(new ExecutionException(String.format("spot request %s fault code(%s) message(%s)",
|
throw new IllegalStateException(String.format("spot request %s fault code(%s) message(%s)", spot.getId(),
|
||||||
spot.getId(), spot.getFaultCode(), spot.getFaultMessage())) {
|
spot.getFaultCode(), spot.getFaultMessage()));
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
});
|
|
||||||
return spot.getState() == SpotInstanceRequest.State.ACTIVE;
|
return spot.getState() == SpotInstanceRequest.State.ACTIVE;
|
||||||
} catch (ResourceNotFoundException e) {
|
} catch (ResourceNotFoundException e) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -78,6 +72,6 @@ public class SpotInstanceRequestActive implements Predicate<SpotInstanceRequest>
|
||||||
|
|
||||||
private SpotInstanceRequest refresh(SpotInstanceRequest spot) {
|
private SpotInstanceRequest refresh(SpotInstanceRequest spot) {
|
||||||
return Iterables.getOnlyElement(client.getSpotInstanceServices().describeSpotInstanceRequestsInRegion(
|
return Iterables.getOnlyElement(client.getSpotInstanceServices().describeSpotInstanceRequestsInRegion(
|
||||||
spot.getRegion(), spot.getId()));
|
spot.getRegion(), spot.getId()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,8 +21,6 @@ package org.jclouds.cloudstack.predicates;
|
||||||
|
|
||||||
import static com.google.common.base.Preconditions.checkNotNull;
|
import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
|
|
||||||
import java.util.concurrent.ExecutionException;
|
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
import javax.inject.Singleton;
|
import javax.inject.Singleton;
|
||||||
|
|
||||||
|
@ -31,7 +29,6 @@ import org.jclouds.cloudstack.domain.AsyncJob;
|
||||||
import org.jclouds.logging.Logger;
|
import org.jclouds.logging.Logger;
|
||||||
|
|
||||||
import com.google.common.base.Predicate;
|
import com.google.common.base.Predicate;
|
||||||
import com.google.common.base.Throwables;
|
|
||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -60,10 +57,8 @@ public class JobComplete implements Predicate<Long> {
|
||||||
return false;
|
return false;
|
||||||
logger.trace("%s: looking for job status %s: currently: %s", job.getId(), 1, job.getStatus());
|
logger.trace("%s: looking for job status %s: currently: %s", job.getId(), 1, job.getStatus());
|
||||||
if (job.getError() != null)
|
if (job.getError() != null)
|
||||||
Throwables.propagate(new ExecutionException(String.format("job %s failed with exception %s", job.getId(), job
|
throw new IllegalStateException(String.format("job %s failed with exception %s", job.getId(), job.getError()
|
||||||
.getError().toString())) {
|
.toString()));
|
||||||
private static final long serialVersionUID = 4371112085613620239L;
|
|
||||||
});
|
|
||||||
return job.getStatus() > 0;
|
return job.getStatus() > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue