Skip to content

Commit 528cc69

Browse files
authored
Merge pull request docker-java#982 from pjdarton/add_netty_read_timeout
Add withReadTimeout(Integer) method to NettyDockerCmdExecFactory
2 parents ecb014e + 6be607c commit 528cc69

File tree

1 file changed

+46
-0
lines changed

1 file changed

+46
-0
lines changed

src/main/java/com/github/dockerjava/netty/NettyDockerCmdExecFactory.java

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@
66
import java.net.InetAddress;
77
import java.net.InetSocketAddress;
88
import java.net.SocketAddress;
9+
import java.net.SocketTimeoutException;
910
import java.security.Security;
11+
import java.util.concurrent.TimeUnit;
1012

1113
import javax.net.ssl.SSLEngine;
1214
import javax.net.ssl.SSLParameters;
@@ -23,6 +25,7 @@
2325
import io.netty.channel.Channel;
2426
import io.netty.channel.ChannelConfig;
2527
import io.netty.channel.ChannelFactory;
28+
import io.netty.channel.ChannelHandlerContext;
2629
import io.netty.channel.ChannelInitializer;
2730
import io.netty.channel.EventLoopGroup;
2831
import io.netty.channel.epoll.EpollDomainSocketChannel;
@@ -38,6 +41,9 @@
3841
import io.netty.handler.codec.http.HttpClientCodec;
3942
import io.netty.handler.logging.LoggingHandler;
4043
import io.netty.handler.ssl.SslHandler;
44+
import io.netty.handler.timeout.IdleState;
45+
import io.netty.handler.timeout.IdleStateEvent;
46+
import io.netty.handler.timeout.IdleStateHandler;
4147
import io.netty.util.concurrent.DefaultThreadFactory;
4248
import org.bouncycastle.jce.provider.BouncyCastleProvider;
4349

@@ -84,6 +90,8 @@ public DuplexChannel getChannel() {
8490

8591
private Integer connectTimeout = null;
8692

93+
private Integer readTimeout = null;
94+
8795
@Override
8896
public void init(DockerClientConfig dockerClientConfig) {
8997
super.init(dockerClientConfig);
@@ -273,16 +281,54 @@ public NettyDockerCmdExecFactory withConnectTimeout(Integer connectTimeout) {
273281
return this;
274282
}
275283

284+
/**
285+
* Configure read timeout in milliseconds
286+
*/
287+
public NettyDockerCmdExecFactory withReadTimeout(Integer readTimeout) {
288+
this.readTimeout = readTimeout;
289+
return this;
290+
}
291+
276292
private <T extends Channel> T configure(T channel) {
277293
ChannelConfig channelConfig = channel.config();
278294

279295
if (connectTimeout != null) {
280296
channelConfig.setConnectTimeoutMillis(connectTimeout);
281297
}
298+
if (readTimeout != null) {
299+
channel.pipeline().addLast("readTimeoutHandler", new ReadTimeoutHandler());
300+
}
282301

283302
return channel;
284303
}
285304

305+
private final class ReadTimeoutHandler extends IdleStateHandler {
306+
private boolean alreadyTimedOut;
307+
308+
ReadTimeoutHandler() {
309+
super(readTimeout, 0, 0, TimeUnit.MILLISECONDS);
310+
}
311+
312+
/**
313+
* Called when a read timeout was detected.
314+
*/
315+
@Override
316+
protected synchronized void channelIdle(ChannelHandlerContext ctx, IdleStateEvent evt) throws Exception {
317+
assert evt.state() == IdleState.READER_IDLE;
318+
final Channel channel = ctx.channel();
319+
if (channel == null || !channel.isActive() || alreadyTimedOut) {
320+
return;
321+
}
322+
final Object dockerAPIEndpoint = dockerClientConfig.getDockerHost();
323+
final String msg = "Read timed out: No data received within " + readTimeout
324+
+ "ms. Perhaps the docker API (" + dockerAPIEndpoint
325+
+ ") is not responding normally, or perhaps you need to increase the readTimeout value.";
326+
final Exception ex = new SocketTimeoutException(msg);
327+
ctx.fireExceptionCaught(ex);
328+
alreadyTimedOut = true;
329+
}
330+
}
331+
286332
protected WebTarget getBaseResource() {
287333
checkNotNull(baseResource, "Factory not initialized, baseResource not set. You probably forgot to call init()!");
288334
return baseResource;

0 commit comments

Comments
 (0)