Type: Bug
Component: AppConfig
Describe the bug
Using Spring Cloud AWS 4.1.0 (io.awspring.cloud:spring-cloud-aws-app-config:4.1.0, io.awspring.cloud:spring-cloud-aws-autoconfigure:4.1.0) with AppConfig reload enabled:
spring:
cloud:
aws:
appconfig:
reload:
strategy: refresh
period: 10s
config:
import:
- aws-appconfig:APP#ENV#PROFILE
AppConfigPropertySource stores the AppConfigData session token in a plain String sessionToken field. init() rotates it correctly:
GetLatestConfigurationResponse response = this.source.getLatestConfiguration(request);
...
sessionToken = response.nextPollConfigurationToken();
However, PollingAwsPropertySourceChangeDetector.executeCycle() never calls init() on the actual AppConfigPropertySource instance registered in the Environment. Every polling cycle it does:
AwsPropertySource copy = source.copy();
copy.init();
if (changed(source, copy)) {
reloadProperties();
}
AppConfigPropertySource.copy() constructs a new instance by copying the current sessionToken value:
public AppConfigPropertySource copy() {
return new AppConfigPropertySource(context, appConfigClient, sessionToken, new LinkedHashMap<>(properties));
}
So copy.init() rotates the token and receives the new nextPollConfigurationToken, but that new token is only stored on the copy, which is discarded at the end of the cycle. The original
instance living in the Environment keeps the same, never-refreshed token forever.
When token is expired, will get exception:
software.amazon.awssdk.services.appconfigdata.model.BadRequestException: Token not valid (Service: AppConfigData, Status Code: 400, Request ID: ...)
at software.amazon.awssdk.services.appconfigdata.DefaultAppConfigDataClient.getLatestConfiguration
at io.awspring.cloud.appconfig.AppConfigPropertySource.init
at io.awspring.cloud.autoconfigure.config.reload.PollingAwsPropertySourceChangeDetector.executeCycle
Suggested fix: share the mutable token state between the original AwsPropertySource and every instance produced by copy(), instead of copying the token value. E.g. change sessionToken from
String to AtomicReference<String>, and have copy() pass the same AtomicReference instance to the new copy:
private final AtomicReference<String> sessionToken;
public AppConfigPropertySource copy() {
return new AppConfigPropertySource(context, appConfigClient, sessionToken, new LinkedHashMap<>(properties));
}
This way, whichever instance (original or copy) successfully rotates the token, all instances sharing that reference see the up-to-date token on the next cycle, while properties (used for change
detection) stays independently copied so changed(source, copy) still works correctly.
Sample
- Configure an app with
spring.cloud.aws.appconfig.reload.strategy=refresh and a short period (e.g. 10s), importing any AppConfig configuration profile.
- Wait until token expire.
- Observe: throws
BadRequestException: Token not valid, repeating on every subsequent cycle.
Type: Bug
Component: AppConfig
Describe the bug
Using Spring Cloud AWS 4.1.0 (
io.awspring.cloud:spring-cloud-aws-app-config:4.1.0,io.awspring.cloud:spring-cloud-aws-autoconfigure:4.1.0) with AppConfig reload enabled:AppConfigPropertySourcestores the AppConfigData session token in a plainString sessionTokenfield.init()rotates it correctly:However,
PollingAwsPropertySourceChangeDetector.executeCycle()never callsinit()on the actualAppConfigPropertySourceinstance registered in theEnvironment. Every polling cycle it does:AppConfigPropertySource.copy()constructs a new instance by copying the currentsessionTokenvalue:So
copy.init()rotates the token and receives the newnextPollConfigurationToken, but that new token is only stored on the copy, which is discarded at the end of the cycle. The originalinstance living in the
Environmentkeeps the same, never-refreshed token forever.When token is expired, will get exception:
Suggested fix: share the mutable token state between the original
AwsPropertySourceand every instance produced bycopy(), instead of copying the token value. E.g. changesessionTokenfromStringtoAtomicReference<String>, and havecopy()pass the sameAtomicReferenceinstance to the new copy:This way, whichever instance (original or copy) successfully rotates the token, all instances sharing that reference see the up-to-date token on the next cycle, while
properties(used for changedetection) stays independently copied so
changed(source, copy)still works correctly.Sample
spring.cloud.aws.appconfig.reload.strategy=refreshand a shortperiod(e.g.10s), importing any AppConfig configuration profile.BadRequestException: Token not valid, repeating on every subsequent cycle.