1 /*
2 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License").
5 * You may not use this file except in compliance with the License.
6 * A copy of the License is located at
7 *
8 * http://aws.amazon.com/apache2.0
9 *
10 * or in the "license" file accompanying this file. This file is distributed
11 * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12 * express or implied. See the License for the specific language governing
13 * permissions and limitations under the License.
14 */
15
16 package software.amazon.awssdk.core.internal.http.timers;
17
18 import java.time.Duration;
19 import java.util.Optional;
20 import java.util.concurrent.CompletableFuture;
21 import java.util.concurrent.ScheduledExecutorService;
22 import java.util.concurrent.ScheduledFuture;
23 import java.util.concurrent.TimeUnit;
24 import java.util.function.Supplier;
25 import software.amazon.awssdk.annotations.SdkInternalApi;
26 import software.amazon.awssdk.core.exception.SdkClientException;
27 import software.amazon.awssdk.utils.OptionalUtils;
28
29 @SdkInternalApi
30 public final class TimerUtils {
31
32 private TimerUtils() {
33 }
34
35 /**
36 * Schedule a {@link TimeoutTask} and exceptional completes a {@link CompletableFuture} with the provide exception
37 * if not otherwise completed before the given timeout.
38 *
39 * @param completableFuture the completableFuture to be timed
40 * @param timeoutExecutor the executor to execute the {@link TimeoutTask}
41 * @param exceptionSupplier the exception to thrown after timeout
42 * @param timeoutInMills the timeout in milliseconds.
43 * @param <T> the type of the {@link CompletableFuture}
44 * @return a {@link TimeoutTracker}
45 */
46 public static <T> TimeoutTracker timeAsyncTaskIfNeeded(CompletableFuture<T> completableFuture,
47 ScheduledExecutorService timeoutExecutor,
48 Supplier<SdkClientException> exceptionSupplier,
49 long timeoutInMills) {
50 if (timeoutInMills <= 0) {
51 return NoOpTimeoutTracker.INSTANCE;
52 }
53
54 TimeoutTask timeoutTask = new AsyncTimeoutTask(completableFuture, exceptionSupplier);
55
56 ScheduledFuture<?> scheduledFuture =
57 timeoutExecutor.schedule(timeoutTask,
58 timeoutInMills,
59 TimeUnit.MILLISECONDS);
60 TimeoutTracker timeoutTracker = new ApiCallTimeoutTracker(timeoutTask, scheduledFuture);
61
62 completableFuture.whenComplete((o, t) -> timeoutTracker.cancel());
63
64 return timeoutTracker;
65 }
66
67 /**
68 * Schedule a {@link TimeoutTask} that aborts the task if not otherwise completed before the given timeout.
69 *
70 * @param timeoutExecutor the executor to execute the {@link TimeoutTask}
71 * @param timeoutInMills the timeout in milliseconds.
72 * @param threadToInterrupt the thread to interrupt
73 * @return a {@link TimeoutTracker}
74 */
75 public static TimeoutTracker timeSyncTaskIfNeeded(ScheduledExecutorService timeoutExecutor,
76 long timeoutInMills,
77 Thread threadToInterrupt) {
78 if (timeoutInMills <= 0) {
79 return NoOpTimeoutTracker.INSTANCE;
80 }
81
82 SyncTimeoutTask timeoutTask = new SyncTimeoutTask(threadToInterrupt);
83
84 ScheduledFuture<?> scheduledFuture =
85 timeoutExecutor.schedule(timeoutTask,
86 timeoutInMills,
87 TimeUnit.MILLISECONDS);
88 return new ApiCallTimeoutTracker(timeoutTask, scheduledFuture);
89 }
90
91 public static long resolveTimeoutInMillis(Supplier<Optional<Duration>> supplier, Duration fallback) {
92 return OptionalUtils.firstPresent(supplier.get(), () -> fallback)
93 .map(Duration::toMillis)
94 .orElse(0L);
95 }
96 }
97