make it explicit we are not going to retry on a general sftp failure

This commit is contained in:
Adrian Cole 2011-07-23 15:33:50 +10:00
parent d5caa414b1
commit 0b60ccf5ac
2 changed files with 38 additions and 10 deletions

View File

@ -24,7 +24,6 @@ import static com.google.common.base.Preconditions.checkState;
import static com.google.common.base.Predicates.instanceOf; import static com.google.common.base.Predicates.instanceOf;
import static com.google.common.base.Predicates.or; import static com.google.common.base.Predicates.or;
import static com.google.common.base.Throwables.getCausalChain; import static com.google.common.base.Throwables.getCausalChain;
import static com.google.common.base.Throwables.getRootCause;
import static com.google.common.collect.Iterables.any; import static com.google.common.collect.Iterables.any;
import java.io.IOException; import java.io.IOException;
@ -53,7 +52,6 @@ import org.jclouds.util.Strings2;
import com.google.common.annotations.VisibleForTesting; import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Predicate; import com.google.common.base.Predicate;
import com.google.common.base.Splitter; import com.google.common.base.Splitter;
import com.google.common.collect.Iterables;
import com.google.common.io.Closeables; import com.google.common.io.Closeables;
import com.google.inject.Inject; import com.google.inject.Inject;
import com.jcraft.jsch.ChannelExec; import com.jcraft.jsch.ChannelExec;
@ -296,8 +294,9 @@ public class JschSshClient implements SshClient {
@Override @Override
public Void create() throws Exception { public Void create() throws Exception {
sftp = acquire(sftpConnection); sftp = acquire(sftpConnection);
InputStream is = checkNotNull(contents.getInput(), "inputstream for path %s", path);
try { try {
sftp.put(checkNotNull(contents.getInput(), "inputstream for path %s", path), path); sftp.put(is, path);
} finally { } finally {
Closeables.closeQuietly(contents); Closeables.closeQuietly(contents);
clear(); clear();
@ -318,20 +317,29 @@ public class JschSshClient implements SshClient {
@VisibleForTesting @VisibleForTesting
boolean shouldRetry(Exception from) { boolean shouldRetry(Exception from) {
final String rootMessage = getRootCause(from).getMessage();
if (rootMessage == null)
return false;
return any(getCausalChain(from), retryPredicate) return any(getCausalChain(from), retryPredicate)
|| Iterables.any(Splitter.on(",").split(retryableMessages), new Predicate<String>() { || any(Splitter.on(",").split(retryableMessages), causalChainHasMessageContaining(from));
}
@VisibleForTesting
Predicate<String> causalChainHasMessageContaining(final Exception from) {
return new Predicate<String>() {
@Override @Override
public boolean apply(String input) { public boolean apply(final String input) {
return rootMessage.indexOf(input) != -1; return any(getCausalChain(from), new Predicate<Throwable>() {
@Override
public boolean apply(Throwable arg0) {
return arg0.getMessage() != null && arg0.getMessage().indexOf(input) != -1;
} }
}); });
} }
};
}
private void backoffForAttempt(int retryAttempt, String message) { private void backoffForAttempt(int retryAttempt, String message) {
backoffLimitedRetryHandler.imposeBackoffExponentialDelay(200L, 2, retryAttempt, sshRetries, message); backoffLimitedRetryHandler.imposeBackoffExponentialDelay(200L, 2, retryAttempt, sshRetries, message);
} }

View File

@ -32,7 +32,9 @@ import org.testng.annotations.Test;
import com.google.inject.Guice; import com.google.inject.Guice;
import com.google.inject.Injector; import com.google.inject.Injector;
import com.google.inject.Module; import com.google.inject.Module;
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.JSchException; import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.SftpException;
/** /**
* *
@ -64,6 +66,8 @@ public class JschSshClientTest {
assert ssh.shouldRetry(new JSchException("io error", new IOException("socket closed"))); assert ssh.shouldRetry(new JSchException("io error", new IOException("socket closed")));
assert ssh.shouldRetry(new JSchException("connect error", new ConnectException("problem"))); assert ssh.shouldRetry(new JSchException("connect error", new ConnectException("problem")));
assert ssh.shouldRetry(new IOException("channel %s is not open", new NullPointerException()));
assert ssh.shouldRetry(new IOException("channel %s is not open", new NullPointerException(null)));
} }
@ -72,4 +76,20 @@ public class JschSshClientTest {
assert ssh.shouldRetry(new JSchException("Session.connect: invalid data")); assert ssh.shouldRetry(new JSchException("Session.connect: invalid data"));
assert ssh.shouldRetry(new JSchException("Session.connect: java.net.SocketException: Connection reset")); assert ssh.shouldRetry(new JSchException("Session.connect: java.net.SocketException: Connection reset"));
} }
public void testDoNotRetryOnGeneralSftpError() {
// http://sourceforge.net/mailarchive/forum.php?thread_name=CAARMrHVhASeku48xoAgWEb-nEpUuYkMA03PoA5TvvFdk%3DjGKMA%40mail.gmail.com&forum_name=jsch-users
assert !ssh.shouldRetry(new SftpException(ChannelSftp.SSH_FX_FAILURE, new NullPointerException().toString()));
}
public void testCausalChainHasMessageContaining() {
assert ssh.causalChainHasMessageContaining(
new JSchException("Session.connect: java.io.IOException: End of IO Stream Read")).apply(
" End of IO Stream Read");
assert ssh.causalChainHasMessageContaining(new JSchException("Session.connect: invalid data")).apply(
" invalid data");
assert ssh.causalChainHasMessageContaining(
new JSchException("Session.connect: java.net.SocketException: Connection reset")).apply("java.net.Socket");
assert !ssh.causalChainHasMessageContaining(new NullPointerException()).apply(" End of IO Stream Read");
}
} }