@Test public void wrappedSinkFlushTimesOut() throws Exception { Sink sink = new ForwardingSink(new Buffer()) { @Override public void flush() throws IOException { try { Thread.sleep(500); } catch (InterruptedException e) { throw new AssertionError(); } } }; AsyncTimeout timeout = new AsyncTimeout(); timeout.timeout(250, TimeUnit.MILLISECONDS); Sink timeoutSink = timeout.sink(sink); try { timeoutSink.flush(); fail(); } catch (InterruptedIOException expected) { } }
@Test public void wrappedSourceCloseTimesOut() throws Exception { Source source = new ForwardingSource(new Buffer()) { @Override public void close() throws IOException { try { Thread.sleep(500); } catch (InterruptedException e) { throw new AssertionError(); } } }; AsyncTimeout timeout = new AsyncTimeout(); timeout.timeout(250, TimeUnit.MILLISECONDS); Source timeoutSource = timeout.source(source); try { timeoutSource.close(); fail(); } catch (InterruptedIOException expected) { } }
@Nullable IOException timeoutExit(@Nullable IOException cause) { if (!timeout.exit()) return cause; InterruptedIOException e = new InterruptedIOException("timeout"); if (cause != null) { e.initCause(cause); } return e; }
/** * Throws an IOException if {@code throwOnTimeout} is {@code true} and a * timeout occurred. See {@link #newTimeoutException(IOException)} * for the type of exception thrown. */ final void exit(boolean throwOnTimeout) throws IOException { boolean timedOut = exit(); if (timedOut && throwOnTimeout) throw newTimeoutException(null); }
private RealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) { this.client = client; this.originalRequest = originalRequest; this.forWebSocket = forWebSocket; this.retryAndFollowUpInterceptor = new RetryAndFollowUpInterceptor(client); this.timeout = new AsyncTimeout() { @Override protected void timedOut() { cancel(); } }; this.timeout.timeout(client.callTimeoutMillis(), MILLISECONDS); }
head = new AsyncTimeout(); new Watchdog().start(); node.timeoutAt = now + Math.min(timeoutNanos, node.deadlineNanoTime() - now); } else if (timeoutNanos != 0) { node.timeoutAt = now + timeoutNanos; } else if (hasDeadline) { node.timeoutAt = node.deadlineNanoTime(); } else { throw new AssertionError(); long remainingNanos = node.remainingNanos(now); for (AsyncTimeout prev = head; true; prev = prev.next) { if (prev.next == null || remainingNanos < prev.next.remainingNanos(now)) { node.next = prev.next; prev.next = node;
/** * Returns a sink that writes to {@code socket}. Prefer this over {@link * #sink(OutputStream)} because this method honors timeouts. When the socket * write times out, the socket is asynchronously closed by a watchdog thread. */ public static Sink sink(Socket socket) throws IOException { if (socket == null) throw new IllegalArgumentException("socket == null"); AsyncTimeout timeout = timeout(socket); Sink sink = sink(socket.getOutputStream(), timeout); return timeout.sink(sink); }
/** * Returns a source that reads from {@code socket}. Prefer this over {@link * #source(InputStream)} because this method honors timeouts. When the socket * read times out, the socket is asynchronously closed by a watchdog thread. */ public static Source source(Socket socket) throws IOException { if (socket == null) throw new IllegalArgumentException("socket == null"); AsyncTimeout timeout = timeout(socket); Source source = source(socket.getInputStream(), timeout); return timeout.source(source); }
/** Returns true if the timeout occurred. */ public final boolean exit() { if (!inQueue) return false; inQueue = false; return cancelScheduledTimeout(this); }
@Override public Response execute() throws IOException { synchronized (this) { if (executed) throw new IllegalStateException("Already Executed"); executed = true; } captureCallStackTrace(); timeout.enter(); eventListener.callStart(this); try { client.dispatcher().executed(this); Response result = getResponseWithInterceptorChain(); if (result == null) throw new IOException("Canceled"); return result; } catch (IOException e) { e = timeoutExit(e); eventListener.callFailed(this, e); throw e; } finally { client.dispatcher().finished(this); } }
@Nullable IOException timeoutExit(@Nullable IOException cause) { if (!timeout.exit()) return cause; InterruptedIOException e = new InterruptedIOException("timeout"); if (cause != null) { e.initCause(cause); } return e; }
/** * Returns either {@code cause} or an IOException that's caused by * {@code cause} if a timeout occurred. See * {@link #newTimeoutException(IOException)} for the type of * exception returned. */ final IOException exit(IOException cause) throws IOException { if (!exit()) return cause; return newTimeoutException(cause); }
@Test public void wrappedSinkCloseTimesOut() throws Exception { Sink sink = new ForwardingSink(new Buffer()) { @Override public void close() throws IOException { try { Thread.sleep(500); } catch (InterruptedException e) { throw new AssertionError(); } } }; AsyncTimeout timeout = new AsyncTimeout(); timeout.timeout(250, TimeUnit.MILLISECONDS); Sink timeoutSink = timeout.sink(sink); try { timeoutSink.close(); fail(); } catch (InterruptedIOException expected) { } }
@Override public Response execute() throws IOException { synchronized (this) { if (executed) throw new IllegalStateException("Already Executed"); executed = true; } captureCallStackTrace(); timeout.enter(); eventListener.callStart(this); try { client.dispatcher().executed(this); Response result = getResponseWithInterceptorChain(); if (result == null) throw new IOException("Canceled"); return result; } catch (IOException e) { e = timeoutExit(e); eventListener.callFailed(this, e); throw e; } finally { client.dispatcher().finished(this); } }
@Test public void wrappedSourceTimesOut() throws Exception { Source source = new ForwardingSource(new Buffer()) { @Override public long read(Buffer sink, long byteCount) throws IOException { try { Thread.sleep(500); return -1; } catch (InterruptedException e) { throw new AssertionError(); } } }; AsyncTimeout timeout = new AsyncTimeout(); timeout.timeout(250, TimeUnit.MILLISECONDS); Source timeoutSource = timeout.source(source); try { timeoutSource.read(new Buffer(), 0); fail(); } catch (InterruptedIOException expected) { } }