Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .brazil.json
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,8 @@
"crt-unavailable-tests": { "skipImport": true },
"bundle-shading-tests": { "skipImport": true },
"architecture-tests": {"skipImport": true},
"s3-tests": {"skipImport": true}
"s3-tests": {"skipImport": true},
"warmup-tests": { "skipImport": true }
},

"dependencies": {
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/dependency-cve-monitor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ jobs:
maven-args: >-
-DtransitiveExcludes=*:*
-DclasspathScope=runtime
-pl !build-tools,!release-scripts,!archetypes,!test/test-utils,!test/sdk-benchmarks,!test/http-client-tests,!test/http-client-benchmarks,!test/s3-benchmarks,!test/protocol-tests-core,!test/ruleset-testing-core,!test/protocol-tests,!test/service-test-utils,!test/codegen-generated-classes-test,!test/sdk-standard-benchmarks,!test/module-path-tests,!test/tests-coverage-reporting,!test/stability-tests,!test/sdk-native-image-test,!test/auth-tests,!test/region-testing,!test/old-client-version-compatibility-test,!test/bundle-logging-bridge-binding-test,!test/v2-migration-tests,!test/bundle-shading-tests,!test/crt-unavailable-tests,!test/architecture-tests,!test/s3-tests
-pl !build-tools,!release-scripts,!archetypes,!test/test-utils,!test/sdk-benchmarks,!test/http-client-tests,!test/http-client-benchmarks,!test/s3-benchmarks,!test/protocol-tests-core,!test/ruleset-testing-core,!test/protocol-tests,!test/service-test-utils,!test/codegen-generated-classes-test,!test/sdk-standard-benchmarks,!test/module-path-tests,!test/tests-coverage-reporting,!test/stability-tests,!test/sdk-native-image-test,!test/auth-tests,!test/region-testing,!test/old-client-version-compatibility-test,!test/bundle-logging-bridge-binding-test,!test/v2-migration-tests,!test/bundle-shading-tests,!test/crt-unavailable-tests,!test/architecture-tests,!test/s3-tests,!test/warmup-tests

notify-alerts:
if: github.repository == 'aws/aws-sdk-java-v2'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import software.amazon.awssdk.annotations.SdkPublicApi;
import software.amazon.awssdk.annotations.ThreadSafe;
import software.amazon.awssdk.core.internal.crac.ClasspathWarmUpInvoker;
import software.amazon.awssdk.core.internal.http.loader.ClasspathHttpWarmupInvoker;

/**
* Entry point for warming up SDK service request paths before a Coordinated Restore at Checkpoint (CRaC)
Expand Down Expand Up @@ -66,6 +67,7 @@ public static void prime() {
}
// Set primed only after invokeAll() succeeds, so a failed run leaves primed false and a later call retries.
ClasspathWarmUpInvoker.create().invokeAll();
ClasspathHttpWarmupInvoker.create().invokeAll();
primed = true;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,10 @@

package software.amazon.awssdk.core.internal.crac;

import java.util.Iterator;
import java.util.ServiceConfigurationError;
import java.util.ServiceLoader;
import software.amazon.awssdk.annotations.SdkInternalApi;
import software.amazon.awssdk.annotations.SdkTestInternalApi;
import software.amazon.awssdk.core.crac.SdkWarmUpProvider;
import software.amazon.awssdk.utils.Logger;

/**
* {@link WarmUpInvoker} implementation that uses {@link ServiceLoader} to find {@link SdkWarmUpProvider}
Expand All @@ -30,8 +27,6 @@
@SdkInternalApi
public final class ClasspathWarmUpInvoker implements WarmUpInvoker {

private static final Logger log = Logger.loggerFor(ClasspathWarmUpInvoker.class);

private final WarmUpServiceLoader serviceLoader;

@SdkTestInternalApi
Expand All @@ -41,30 +36,7 @@ public final class ClasspathWarmUpInvoker implements WarmUpInvoker {

@Override
public void invokeAll() {
Iterator<SdkWarmUpProvider> iterator = serviceLoader.loadProviders();
boolean invokedAny = false;

while (iterator.hasNext()) {
SdkWarmUpProvider provider;
try {
provider = iterator.next();
} catch (ServiceConfigurationError e) {
// next() has already advanced past the bad provider, so it is safe to continue to the next one.
log.warn(() -> "Skipping an SdkWarmUpProvider that could not be loaded.", e);
continue;
}

invokedAny = true;
try {
provider.warmUp();
} catch (RuntimeException e) {
log.warn(() -> "An SdkWarmUpProvider failed during warmUp() and was skipped.", e);
}
}

if (!invokedAny) {
log.debug(() -> "No SdkWarmUpProvider implementations were discovered on the classpath.");
}
WarmUpDiscovery.forEachDiscovered(serviceLoader.loadProviders(), SdkWarmUpProvider::warmUp);
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/*
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/

package software.amazon.awssdk.core.internal.crac;

import java.net.URI;
import software.amazon.awssdk.annotations.SdkInternalApi;
import software.amazon.awssdk.core.SdkSystemSetting;
import software.amazon.awssdk.utils.HostnameValidator;
import software.amazon.awssdk.utils.Logger;
import software.amazon.awssdk.utils.StringUtils;

/**
* Resolves the endpoint used by the CRaC HTTP-client warm-up. The warm-up targets a single predetermined service; that service
* is currently STS, so this builds the regional STS endpoint ({@code https://sts.<region>.amazonaws.com/}).
*
* <p>The region is taken from {@link SdkSystemSetting#AWS_REGION} (the {@code aws.region} system property or {@code AWS_REGION}
* environment variable), falling back to {@value #DEFAULT_REGION} when it is unset or not a valid hostname component. This
* matches how the SDK resolves a region from system settings.
*
* <p>Only system properties and environment variables are read. The full SDK region-resolution chain (IMDS, profile file) is
* avoided during priming because those add network or filesystem calls that may fail or time out. The endpoint host always
* uses the {@code amazonaws.com} suffix, which is incorrect for the China, GovCloud, and ISO partitions; in those partitions
* the warm-up request simply fails and is ignored, since it is best-effort.
*/
@SdkInternalApi
public final class RegionEndpointResolver {

static final String DEFAULT_REGION = "us-east-1";

private static final Logger log = Logger.loggerFor(RegionEndpointResolver.class);

private RegionEndpointResolver() {
}

public static RegionEndpointResolver create() {
return new RegionEndpointResolver();
}

/**
* @return the regional STS endpoint URI for the resolved region; never null.
*/
public URI endpoint() {
return URI.create("https://sts." + resolveRegion() + ".amazonaws.com/");
}

private String resolveRegion() {
// trimToNull turns blank/empty into null so a blank AWS_REGION falls through to the default.
String awsRegion = SdkSystemSetting.AWS_REGION.getStringValue()
.map(StringUtils::trimToNull)
.orElse(null);
if (awsRegion == null) {
return DEFAULT_REGION;
}
// A real region is a hostname-compliant token. Reject anything else so it cannot alter the endpoint host, and fall
// back to the default so the best-effort warm-up still runs.
try {
HostnameValidator.validateHostnameCompliant(awsRegion, "region", "AWS_REGION");
return awsRegion;
} catch (IllegalArgumentException e) {
log.debug(() -> "Configured region is not a valid hostname component; using " + DEFAULT_REGION + " for warm-up.", e);
return DEFAULT_REGION;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/*
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/

package software.amazon.awssdk.core.internal.crac;

import java.util.Iterator;
import java.util.ServiceConfigurationError;
import java.util.function.Consumer;
import software.amazon.awssdk.annotations.SdkInternalApi;
import software.amazon.awssdk.utils.Logger;

/**
* Shared best-effort {@link java.util.ServiceLoader} iteration for the CRaC warm-up paths.
*/
@SdkInternalApi
public final class WarmUpDiscovery {

private static final Logger log = Logger.loggerFor(WarmUpDiscovery.class);

private WarmUpDiscovery() {
}

/**
* Applies {@code action} to every discovered element, skipping (and logging at warn) any element that fails to load or
* whose action throws, so the rest still run. Logs at debug when nothing is discovered.
*/
public static <T> void forEachDiscovered(Iterator<T> iterator, Consumer<T> action) {
boolean discoveredAny = false;
while (iterator.hasNext()) {
T element;
try {
element = iterator.next();
} catch (ServiceConfigurationError e) {
// next() has already advanced past the bad element, so it is safe to continue to the next one.
log.warn(() -> "Skipping a warm-up task that could not be loaded.", e);
continue;
}

discoveredAny = true;
T discovered = element;
try {
action.accept(discovered);
} catch (RuntimeException | LinkageError e) {
// LinkageError because a discovered element can fail to link (missing deps/native lib, failed static init),
// which is an Error, not an Exception. Skip it to keep warm-up best-effort; fatal Errors still propagate.
log.warn(() -> "Warm-up failed for " + discovered.getClass().getName() + " and was skipped.", e);
}
}

if (!discoveredAny) {
log.debug(() -> "No warm-up tasks were discovered on the classpath.");
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/

package software.amazon.awssdk.core.internal.http.loader;

import java.util.Collections;
import java.util.List;
import software.amazon.awssdk.annotations.SdkInternalApi;
import software.amazon.awssdk.annotations.SdkTestInternalApi;

/**
* {@link HttpWarmupInvoker} that owns the set of {@link HttpClientWarmer}s and invokes each.
*/
@SdkInternalApi
public final class ClasspathHttpWarmupInvoker implements HttpWarmupInvoker {

private final List<HttpClientWarmer> warmers;

@SdkTestInternalApi
ClasspathHttpWarmupInvoker(List<HttpClientWarmer> warmers) {
this.warmers = warmers;
}

/**
* @return an invoker over the HTTP-client warmers on the classpath.
*/
public static HttpWarmupInvoker create() {
return new ClasspathHttpWarmupInvoker(Collections.singletonList(SyncHttpClientWarmer.create()));
}

@Override
public void invokeAll() {
for (HttpClientWarmer warmer : warmers) {
warmer.warmAll();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/

package software.amazon.awssdk.core.internal.http.loader;

import software.amazon.awssdk.annotations.SdkInternalApi;

/**
* Warms the sync or async HTTP clients on the classpath for CRaC priming.
*/
@SdkInternalApi
public interface HttpClientWarmer {

/**
* Warms every HTTP client found on the classpath. Best-effort; never throws.
*/
void warmAll();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/

package software.amazon.awssdk.core.internal.http.loader;

import software.amazon.awssdk.annotations.SdkInternalApi;

/**
* Warms every HTTP client on the classpath for CRaC priming by invoking each {@link HttpClientWarmer}.
*/
@SdkInternalApi
public interface HttpWarmupInvoker {

/**
* Invokes {@link HttpClientWarmer#warmAll()} on every warmer. Best-effort; never throws.
*/
void invokeAll();
}
Loading
Loading