001/* 002 * Copyright (C) 2006 The Guava Authors 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 005 * in compliance with the License. You may obtain a copy of the License at 006 * 007 * http://www.apache.org/licenses/LICENSE-2.0 008 * 009 * Unless required by applicable law or agreed to in writing, software distributed under the License 010 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 011 * or implied. See the License for the specific language governing permissions and limitations under 012 * the License. 013 */ 014 015package com.google.common.util.concurrent; 016 017import static com.google.common.util.concurrent.Internal.toNanosSaturated; 018 019import com.google.common.annotations.Beta; 020import com.google.common.annotations.GwtIncompatible; 021import com.google.errorprone.annotations.CanIgnoreReturnValue; 022import com.google.errorprone.annotations.DoNotMock; 023import java.time.Duration; 024import java.util.concurrent.Callable; 025import java.util.concurrent.ExecutionException; 026import java.util.concurrent.TimeUnit; 027import java.util.concurrent.TimeoutException; 028import org.checkerframework.checker.nullness.qual.Nullable; 029 030/** 031 * Imposes a time limit on method calls. 032 * 033 * @author Kevin Bourrillion 034 * @author Jens Nyman 035 * @since 1.0 036 */ 037@Beta 038@DoNotMock("Use FakeTimeLimiter") 039@GwtIncompatible 040@ElementTypesAreNonnullByDefault 041public interface TimeLimiter { 042 043 /** 044 * Returns an instance of {@code interfaceType} that delegates all method calls to the {@code 045 * target} object, enforcing the specified time limit on each call. This time-limited delegation 046 * is also performed for calls to {@link Object#equals}, {@link Object#hashCode}, and {@link 047 * Object#toString}. 048 * 049 * <p>If the target method call finishes before the limit is reached, the return value or 050 * exception is propagated to the caller exactly as-is. If, on the other hand, the time limit is 051 * reached, the proxy will attempt to abort the call to the target, and will throw an {@link 052 * UncheckedTimeoutException} to the caller. 053 * 054 * <p>It is important to note that the primary purpose of the proxy object is to return control to 055 * the caller when the timeout elapses; aborting the target method call is of secondary concern. 056 * The particular nature and strength of the guarantees made by the proxy is 057 * implementation-dependent. However, it is important that each of the methods on the target 058 * object behaves appropriately when its thread is interrupted. 059 * 060 * <p>For example, to return the value of {@code target.someMethod()}, but substitute {@code 061 * DEFAULT_VALUE} if this method call takes over 50 ms, you can use this code: 062 * 063 * <pre> 064 * TimeLimiter limiter = . . .; 065 * TargetType proxy = limiter.newProxy( 066 * target, TargetType.class, 50, TimeUnit.MILLISECONDS); 067 * try { 068 * return proxy.someMethod(); 069 * } catch (UncheckedTimeoutException e) { 070 * return DEFAULT_VALUE; 071 * } 072 * </pre> 073 * 074 * @param target the object to proxy 075 * @param interfaceType the interface you wish the returned proxy to implement 076 * @param timeoutDuration with timeoutUnit, the maximum length of time that callers are willing to 077 * wait on each method call to the proxy 078 * @param timeoutUnit with timeoutDuration, the maximum length of time that callers are willing to 079 * wait on each method call to the proxy 080 * @return a time-limiting proxy 081 * @throws IllegalArgumentException if {@code interfaceType} is a regular class, enum, or 082 * annotation type, rather than an interface 083 */ 084 @SuppressWarnings("GoodTime") // should accept a java.time.Duration 085 <T> T newProxy(T target, Class<T> interfaceType, long timeoutDuration, TimeUnit timeoutUnit); 086 087 /** 088 * Returns an instance of {@code interfaceType} that delegates all method calls to the {@code 089 * target} object, enforcing the specified time limit on each call. This time-limited delegation 090 * is also performed for calls to {@link Object#equals}, {@link Object#hashCode}, and {@link 091 * Object#toString}. 092 * 093 * <p>If the target method call finishes before the limit is reached, the return value or 094 * exception is propagated to the caller exactly as-is. If, on the other hand, the time limit is 095 * reached, the proxy will attempt to abort the call to the target, and will throw an {@link 096 * UncheckedTimeoutException} to the caller. 097 * 098 * <p>It is important to note that the primary purpose of the proxy object is to return control to 099 * the caller when the timeout elapses; aborting the target method call is of secondary concern. 100 * The particular nature and strength of the guarantees made by the proxy is 101 * implementation-dependent. However, it is important that each of the methods on the target 102 * object behaves appropriately when its thread is interrupted. 103 * 104 * <p>For example, to return the value of {@code target.someMethod()}, but substitute {@code 105 * DEFAULT_VALUE} if this method call takes over 50 ms, you can use this code: 106 * 107 * <pre> 108 * TimeLimiter limiter = . . .; 109 * TargetType proxy = limiter.newProxy(target, TargetType.class, Duration.ofMillis(50)); 110 * try { 111 * return proxy.someMethod(); 112 * } catch (UncheckedTimeoutException e) { 113 * return DEFAULT_VALUE; 114 * } 115 * </pre> 116 * 117 * @param target the object to proxy 118 * @param interfaceType the interface you wish the returned proxy to implement 119 * @param timeout the maximum length of time that callers are willing to wait on each method call 120 * to the proxy 121 * @return a time-limiting proxy 122 * @throws IllegalArgumentException if {@code interfaceType} is a regular class, enum, or 123 * annotation type, rather than an interface 124 * @since 28.0 125 */ 126 default <T> T newProxy(T target, Class<T> interfaceType, Duration timeout) { 127 return newProxy(target, interfaceType, toNanosSaturated(timeout), TimeUnit.NANOSECONDS); 128 } 129 130 /** 131 * Invokes a specified Callable, timing out after the specified time limit. If the target method 132 * call finishes before the limit is reached, the return value or a wrapped exception is 133 * propagated. If, on the other hand, the time limit is reached, we attempt to abort the call to 134 * the target, and throw a {@link TimeoutException} to the caller. 135 * 136 * @param callable the Callable to execute 137 * @param timeoutDuration with timeoutUnit, the maximum length of time to wait 138 * @param timeoutUnit with timeoutDuration, the maximum length of time to wait 139 * @return the result returned by the Callable 140 * @throws TimeoutException if the time limit is reached 141 * @throws InterruptedException if the current thread was interrupted during execution 142 * @throws ExecutionException if {@code callable} throws a checked exception 143 * @throws UncheckedExecutionException if {@code callable} throws a {@code RuntimeException} 144 * @throws ExecutionError if {@code callable} throws an {@code Error} 145 * @since 22.0 146 */ 147 @SuppressWarnings("GoodTime") // should accept a java.time.Duration 148 @CanIgnoreReturnValue 149 <T extends @Nullable Object> T callWithTimeout( 150 Callable<T> callable, long timeoutDuration, TimeUnit timeoutUnit) 151 throws TimeoutException, InterruptedException, ExecutionException; 152 153 /** 154 * Invokes a specified Callable, timing out after the specified time limit. If the target method 155 * call finishes before the limit is reached, the return value or a wrapped exception is 156 * propagated. If, on the other hand, the time limit is reached, we attempt to abort the call to 157 * the target, and throw a {@link TimeoutException} to the caller. 158 * 159 * @param callable the Callable to execute 160 * @param timeout the maximum length of time to wait 161 * @return the result returned by the Callable 162 * @throws TimeoutException if the time limit is reached 163 * @throws InterruptedException if the current thread was interrupted during execution 164 * @throws ExecutionException if {@code callable} throws a checked exception 165 * @throws UncheckedExecutionException if {@code callable} throws a {@code RuntimeException} 166 * @throws ExecutionError if {@code callable} throws an {@code Error} 167 * @since 28.0 168 */ 169 @CanIgnoreReturnValue 170 default <T extends @Nullable Object> T callWithTimeout(Callable<T> callable, Duration timeout) 171 throws TimeoutException, InterruptedException, ExecutionException { 172 return callWithTimeout(callable, toNanosSaturated(timeout), TimeUnit.NANOSECONDS); 173 } 174 175 /** 176 * Invokes a specified Callable, timing out after the specified time limit. If the target method 177 * call finishes before the limit is reached, the return value or a wrapped exception is 178 * propagated. If, on the other hand, the time limit is reached, we attempt to abort the call to 179 * the target, and throw a {@link TimeoutException} to the caller. 180 * 181 * <p>The difference with {@link #callWithTimeout(Callable, long, TimeUnit)} is that this method 182 * will ignore interrupts on the current thread. 183 * 184 * @param callable the Callable to execute 185 * @param timeoutDuration with timeoutUnit, the maximum length of time to wait 186 * @param timeoutUnit with timeoutDuration, the maximum length of time to wait 187 * @return the result returned by the Callable 188 * @throws TimeoutException if the time limit is reached 189 * @throws ExecutionException if {@code callable} throws a checked exception 190 * @throws UncheckedExecutionException if {@code callable} throws a {@code RuntimeException} 191 * @throws ExecutionError if {@code callable} throws an {@code Error} 192 * @since 22.0 193 */ 194 @SuppressWarnings("GoodTime") // should accept a java.time.Duration 195 @CanIgnoreReturnValue 196 <T extends @Nullable Object> T callUninterruptiblyWithTimeout( 197 Callable<T> callable, long timeoutDuration, TimeUnit timeoutUnit) 198 throws TimeoutException, ExecutionException; 199 200 /** 201 * Invokes a specified Callable, timing out after the specified time limit. If the target method 202 * call finishes before the limit is reached, the return value or a wrapped exception is 203 * propagated. If, on the other hand, the time limit is reached, we attempt to abort the call to 204 * the target, and throw a {@link TimeoutException} to the caller. 205 * 206 * <p>The difference with {@link #callWithTimeout(Callable, Duration)} is that this method will 207 * ignore interrupts on the current thread. 208 * 209 * @param callable the Callable to execute 210 * @param timeout the maximum length of time to wait 211 * @return the result returned by the Callable 212 * @throws TimeoutException if the time limit is reached 213 * @throws ExecutionException if {@code callable} throws a checked exception 214 * @throws UncheckedExecutionException if {@code callable} throws a {@code RuntimeException} 215 * @throws ExecutionError if {@code callable} throws an {@code Error} 216 * @since 28.0 217 */ 218 @CanIgnoreReturnValue 219 default <T extends @Nullable Object> T callUninterruptiblyWithTimeout( 220 Callable<T> callable, Duration timeout) throws TimeoutException, ExecutionException { 221 return callUninterruptiblyWithTimeout( 222 callable, toNanosSaturated(timeout), TimeUnit.NANOSECONDS); 223 } 224 225 /** 226 * Invokes a specified Runnable, timing out after the specified time limit. If the target method 227 * run finishes before the limit is reached, this method returns or a wrapped exception is 228 * propagated. If, on the other hand, the time limit is reached, we attempt to abort the run, and 229 * throw a {@link TimeoutException} to the caller. 230 * 231 * @param runnable the Runnable to execute 232 * @param timeoutDuration with timeoutUnit, the maximum length of time to wait 233 * @param timeoutUnit with timeoutDuration, the maximum length of time to wait 234 * @throws TimeoutException if the time limit is reached 235 * @throws InterruptedException if the current thread was interrupted during execution 236 * @throws UncheckedExecutionException if {@code runnable} throws a {@code RuntimeException} 237 * @throws ExecutionError if {@code runnable} throws an {@code Error} 238 * @since 22.0 239 */ 240 @SuppressWarnings("GoodTime") // should accept a java.time.Duration 241 void runWithTimeout(Runnable runnable, long timeoutDuration, TimeUnit timeoutUnit) 242 throws TimeoutException, InterruptedException; 243 244 /** 245 * Invokes a specified Runnable, timing out after the specified time limit. If the target method 246 * run finishes before the limit is reached, this method returns or a wrapped exception is 247 * propagated. If, on the other hand, the time limit is reached, we attempt to abort the run, and 248 * throw a {@link TimeoutException} to the caller. 249 * 250 * @param runnable the Runnable to execute 251 * @param timeout the maximum length of time to wait 252 * @throws TimeoutException if the time limit is reached 253 * @throws InterruptedException if the current thread was interrupted during execution 254 * @throws UncheckedExecutionException if {@code runnable} throws a {@code RuntimeException} 255 * @throws ExecutionError if {@code runnable} throws an {@code Error} 256 * @since 28.0 257 */ 258 default void runWithTimeout(Runnable runnable, Duration timeout) 259 throws TimeoutException, InterruptedException { 260 runWithTimeout(runnable, toNanosSaturated(timeout), TimeUnit.NANOSECONDS); 261 } 262 263 /** 264 * Invokes a specified Runnable, timing out after the specified time limit. If the target method 265 * run finishes before the limit is reached, this method returns or a wrapped exception is 266 * propagated. If, on the other hand, the time limit is reached, we attempt to abort the run, and 267 * throw a {@link TimeoutException} to the caller. 268 * 269 * <p>The difference with {@link #runWithTimeout(Runnable, long, TimeUnit)} is that this method 270 * will ignore interrupts on the current thread. 271 * 272 * @param runnable the Runnable to execute 273 * @param timeoutDuration with timeoutUnit, the maximum length of time to wait 274 * @param timeoutUnit with timeoutDuration, the maximum length of time to wait 275 * @throws TimeoutException if the time limit is reached 276 * @throws UncheckedExecutionException if {@code runnable} throws a {@code RuntimeException} 277 * @throws ExecutionError if {@code runnable} throws an {@code Error} 278 * @since 22.0 279 */ 280 @SuppressWarnings("GoodTime") // should accept a java.time.Duration 281 void runUninterruptiblyWithTimeout(Runnable runnable, long timeoutDuration, TimeUnit timeoutUnit) 282 throws TimeoutException; 283 284 /** 285 * Invokes a specified Runnable, timing out after the specified time limit. If the target method 286 * run finishes before the limit is reached, this method returns or a wrapped exception is 287 * propagated. If, on the other hand, the time limit is reached, we attempt to abort the run, and 288 * throw a {@link TimeoutException} to the caller. 289 * 290 * <p>The difference with {@link #runWithTimeout(Runnable, Duration)} is that this method will 291 * ignore interrupts on the current thread. 292 * 293 * @param runnable the Runnable to execute 294 * @param timeout the maximum length of time to wait 295 * @throws TimeoutException if the time limit is reached 296 * @throws UncheckedExecutionException if {@code runnable} throws a {@code RuntimeException} 297 * @throws ExecutionError if {@code runnable} throws an {@code Error} 298 * @since 28.0 299 */ 300 default void runUninterruptiblyWithTimeout(Runnable runnable, Duration timeout) 301 throws TimeoutException { 302 runUninterruptiblyWithTimeout(runnable, toNanosSaturated(timeout), TimeUnit.NANOSECONDS); 303 } 304}