|
| 1 | +package software.amazon.codeguruprofiler.profilinggroup; |
| 2 | + |
| 3 | +import software.amazon.awssdk.core.client.config.ClientOverrideConfiguration; |
| 4 | +import software.amazon.awssdk.core.internal.retry.SdkDefaultRetrySetting; |
| 5 | +import software.amazon.awssdk.core.retry.RetryPolicy; |
| 6 | +import software.amazon.awssdk.core.retry.backoff.BackoffStrategy; |
| 7 | +import software.amazon.awssdk.core.retry.backoff.EqualJitterBackoffStrategy; |
| 8 | +import software.amazon.awssdk.http.SdkHttpClient; |
| 9 | +import software.amazon.awssdk.http.apache.ApacheHttpClient; |
| 10 | +import software.amazon.awssdk.services.codeguruprofiler.CodeGuruProfilerClient; |
| 11 | + |
| 12 | +import java.time.Duration; |
| 13 | + |
| 14 | +public class CodeGuruProfilerClientBuilder { |
| 15 | + // Following what we do at https://tiny.amazon.com/c1ma38jp/codeamazpackSkySblobmainsrc |
| 16 | + |
| 17 | + /** |
| 18 | + * We use an equal-jitter exponential backoff strategy, with a base delay of 100 ms. And, the max backoff time is |
| 19 | + * set to 1 s. So, the retry pattern would be like this: 50 - 100 ms, 100 - 200 ms, 200 - 400 ms, 400 - 800 ms, 500 |
| 20 | + * - 1000 ms, 500 - 1000 ms ... until the request succeeds or until the overall execution timeout or until we run |
| 21 | + * out of retries. |
| 22 | + * |
| 23 | + * The default in the SDK is a full-jitter backoff strategy in which the minimum backoff delay is 0ms (allows instant retries), |
| 24 | + * and uses a max backoff of 20 seconds. |
| 25 | + */ |
| 26 | + private static final Duration BASE_DELAY_MS = Duration.ofMillis(100); // Default: 100ms |
| 27 | + private static final Duration MAX_BACKOFF_MS = Duration.ofMillis(1000); // Default: 20 seconds |
| 28 | + |
| 29 | + /** |
| 30 | + * Setting this to the max retries supported by the SDK. Note that we would timeout well before we do these many |
| 31 | + * retries since we are bound by the overall request timeout. |
| 32 | + */ |
| 33 | + private static final int MAX_ERROR_RETRY = 30; // Default: 3 (for most services) |
| 34 | + |
| 35 | + /** |
| 36 | + * See https://tiny.amazon.com/vlswgwgb/codeamazpackSkySbloba96fsrc |
| 37 | + * for more details on the individual call timeouts. |
| 38 | + */ |
| 39 | + private static final Duration OVERALL_TIMEOUT = Duration.ofMillis(10000); // We can handle more here compared to our API. |
| 40 | + private static final Duration ATTEMPT_TIMEOUT = Duration.ofMillis(500); |
| 41 | + |
| 42 | + /** |
| 43 | + * Maximum amount of time that the client waits for the underlying HTTP client to establish a TCP connection. |
| 44 | + * We want connection issues to time out quickly so that they can be retried like other failures. We can rely |
| 45 | + * on fast network since our calls are intra-region. |
| 46 | + */ |
| 47 | + private static final Duration CONNECTION_TIMEOUT = Duration.ofMillis(500); // Default: 10 seconds |
| 48 | + |
| 49 | + /** |
| 50 | + * The maximum amount of time that the HTTP client waits to read data from an already-established TCP connection. |
| 51 | + * This is the time between when an HTTP POST ends and the entire response of the request is received, and it |
| 52 | + * includes the service and network round-trip times. |
| 53 | + * |
| 54 | + * The general recommendation is to set this value a little higher than the ATTEMPT_TIMEOUT setting if they are used together. |
| 55 | + */ |
| 56 | + private static final Duration SOCKET_TIMEOUT = Duration.ofMillis(600); // Default: 30s |
| 57 | + |
| 58 | + |
| 59 | + private static RetryPolicy getRetryPolicy() { |
| 60 | + BackoffStrategy failureBackoffStrategy = EqualJitterBackoffStrategy.builder() |
| 61 | + .baseDelay(BASE_DELAY_MS) |
| 62 | + .maxBackoffTime(MAX_BACKOFF_MS) |
| 63 | + .build(); |
| 64 | + BackoffStrategy throttlingBackoffStrategy = EqualJitterBackoffStrategy.builder() |
| 65 | + .baseDelay(SdkDefaultRetrySetting.THROTTLED_BASE_DELAY) // 500ms |
| 66 | + .maxBackoffTime(MAX_BACKOFF_MS) |
| 67 | + .build(); |
| 68 | + |
| 69 | + return RetryPolicy.defaultRetryPolicy().toBuilder() |
| 70 | + .backoffStrategy(failureBackoffStrategy) |
| 71 | + .throttlingBackoffStrategy(throttlingBackoffStrategy) |
| 72 | + .numRetries(MAX_ERROR_RETRY) // We can be a bit slower in CloudFormation for the sake of not failing the deployment! |
| 73 | + .build(); |
| 74 | + } |
| 75 | + |
| 76 | + private static SdkHttpClient getHttpClient() { |
| 77 | + return ApacheHttpClient.builder() |
| 78 | + .connectionTimeout(CONNECTION_TIMEOUT) |
| 79 | + .socketTimeout(SOCKET_TIMEOUT) |
| 80 | + .build(); |
| 81 | + } |
| 82 | + |
| 83 | + public static CodeGuruProfilerClient create() { |
| 84 | + return CodeGuruProfilerClient.builder() |
| 85 | + .overrideConfiguration(ClientOverrideConfiguration.builder() |
| 86 | + .retryPolicy(getRetryPolicy()) |
| 87 | + .apiCallTimeout(OVERALL_TIMEOUT) |
| 88 | + .apiCallAttemptTimeout(ATTEMPT_TIMEOUT) |
| 89 | + .build()) |
| 90 | + .httpClient(getHttpClient()) |
| 91 | + .build(); |
| 92 | + } |
| 93 | +} |
0 commit comments