Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@
<artifactId>spring-boot-autoconfigure</artifactId>
<version>3.3.2</version> <!-- {x-version-update;springboot3_org.springframework.boot:spring-boot-autoconfigure;external_dependency} -->
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<version>3.3.2</version> <!-- {x-version-update;springboot3_org.springframework.boot:spring-boot-configuration-processor;external_dependency} -->
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bootstrap</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ class AppConfigurationApplicationSettingPropertySource extends AppConfigurationP
* @param keyPrefixTrimValues prefixs to trim from key values
* @throws InvalidConfigurationPropertyValueException thrown if fails to parse Json content type
*/
public void initProperties(List<String> keyPrefixTrimValues) throws InvalidConfigurationPropertyValueException {
public void initProperties(List<String> keyPrefixTrimValues, boolean isRefresh) throws InvalidConfigurationPropertyValueException {

List<String> labels = Arrays.asList(labelFilters);
// Reverse labels so they have the right priority order.
Expand All @@ -70,7 +70,7 @@ public void initProperties(List<String> keyPrefixTrimValues) throws InvalidConfi
SettingSelector settingSelector = new SettingSelector().setKeyFilter(keyFilter + "*").setLabelFilter(label);

// * for wildcard match
processConfigurationSettings(replicaClient.listSettings(settingSelector), settingSelector.getKeyFilter(),
processConfigurationSettings(replicaClient.listSettings(settingSelector, isRefresh), settingSelector.getKeyFilter(),
keyPrefixTrimValues);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,5 +55,5 @@ protected static String getLabelName(String[] labelFilters) {
return String.join(",", labelFilters);
}

protected abstract void initProperties(List<String> trim) throws InvalidConfigurationPropertyValueException;
protected abstract void initProperties(List<String> trim, boolean isRefresh) throws InvalidConfigurationPropertyValueException;
}
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ private void setupMonitoring(ConfigStore configStore, AppConfigurationReplicaCli
if (monitoring.isEnabled()) {
// Setting new ETag values for Watch
List<ConfigurationSetting> watchKeysSettings = monitoring.getTriggers().stream()
.map(trigger -> client.getWatchKey(trigger.getKey(), trigger.getLabel())).toList();
.map(trigger -> client.getWatchKey(trigger.getKey(), trigger.getLabel(), !STARTUP.get())).toList();

newState.setState(configStore.getEndpoint(), watchKeysSettings, monitoring.getRefreshInterval());
}
Expand Down Expand Up @@ -258,7 +258,7 @@ private List<AppConfigurationPropertySource> createSettings(AppConfigurationRepl
selectedKeys.getKeyFilter() + store.getEndpoint() + "/", client, keyVaultClientFactory,
selectedKeys.getKeyFilter(), selectedKeys.getLabelFilter(profiles));
}
propertySource.initProperties(store.getTrimKeyPrefix());
propertySource.initProperties(store.getTrimKeyPrefix(), !STARTUP.get());
sourceList.add(propertySource);

}
Expand All @@ -281,7 +281,7 @@ private List<FeatureFlags> createFeatureFlags(AppConfigurationReplicaClient clie
if (store.getFeatureFlags().getEnabled()) {
for (FeatureFlagKeyValueSelector selectedKeys : store.getFeatureFlags().getSelects()) {
List<FeatureFlags> storesFeatureFlags = featureFlagClient.loadFeatureFlags(client,
selectedKeys.getKeyFilter(), selectedKeys.getLabelFilter(profiles));
selectedKeys.getKeyFilter(), selectedKeys.getLabelFilter(profiles), !STARTUP.get());
storesFeatureFlags.forEach(featureFlags -> featureFlags.setConfigStore(store));
featureFlagWatchKeys.addAll(storesFeatureFlags);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
import com.azure.spring.cloud.appconfiguration.config.AppConfigurationStoreHealth;
import com.azure.spring.cloud.appconfiguration.config.implementation.AppConfigurationRefreshUtil.RefreshEventData;
import com.azure.spring.cloud.appconfiguration.config.implementation.autofailover.ReplicaLookUp;
import com.azure.spring.cloud.appconfiguration.config.implementation.http.policy.BaseAppConfigurationPolicy;

import reactor.core.publisher.Mono;

Expand Down Expand Up @@ -110,7 +109,6 @@ public void expireRefreshInterval(String endpoint, String syncToken) {
*/
private boolean refreshStores() {
if (running.compareAndSet(false, true)) {
BaseAppConfigurationPolicy.setWatchRequests(true);
try {
RefreshEventData eventData = refreshUtils.refreshStoresCheck(clientFactory,
refreshInterval, defaultMinBackoff, replicaLookUp);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
import com.azure.spring.cloud.appconfiguration.config.implementation.autofailover.ReplicaLookUp;
import com.azure.spring.cloud.appconfiguration.config.implementation.feature.FeatureFlagState;
import com.azure.spring.cloud.appconfiguration.config.implementation.feature.FeatureFlags;
import com.azure.spring.cloud.appconfiguration.config.implementation.http.policy.BaseAppConfigurationPolicy;
import com.azure.spring.cloud.appconfiguration.config.implementation.properties.AppConfigurationStoreMonitoring;
import com.azure.spring.cloud.appconfiguration.config.implementation.properties.FeatureFlagStore;

Expand All @@ -32,7 +31,6 @@ public class AppConfigurationRefreshUtil {
RefreshEventData refreshStoresCheck(AppConfigurationReplicaClientFactory clientFactory, Duration refreshInterval,
Long defaultMinBackoff, ReplicaLookUp replicaLookUp) {
RefreshEventData eventData = new RefreshEventData();
BaseAppConfigurationPolicy.setWatchRequests(true);

try {
if (refreshInterval != null && StateHolder.getNextForcedRefresh() != null
Expand Down Expand Up @@ -178,7 +176,7 @@ private static void refreshWithTime(AppConfigurationReplicaClient client, State
private static void refreshWithoutTime(AppConfigurationReplicaClient client, List<ConfigurationSetting> watchKeys,
RefreshEventData eventData) throws AppConfigurationStatusException {
for (ConfigurationSetting watchKey : watchKeys) {
ConfigurationSetting watchedKey = client.getWatchKey(watchKey.getKey(), watchKey.getLabel());
ConfigurationSetting watchedKey = client.getWatchKey(watchKey.getKey(), watchKey.getLabel(), true);

// If there is no result, etag will be considered empty.
// A refresh will trigger once the selector returns a value.
Expand All @@ -200,7 +198,7 @@ private static void refreshWithTimeFeatureFlags(AppConfigurationReplicaClient cl

for (FeatureFlags featureFlags : state.getWatchKeys()) {

if (client.checkWatchKeys(featureFlags.getSettingSelector())) {
if (client.checkWatchKeys(featureFlags.getSettingSelector(), true)) {
String eventDataInfo = ".appconfig.featureflag/*";

// Only one refresh Event needs to be call to update all of the
Expand All @@ -222,7 +220,7 @@ private static void refreshWithoutTimeFeatureFlags(AppConfigurationReplicaClient

for (FeatureFlags featureFlags : watchKeys.getWatchKeys()) {

if (client.checkWatchKeys(featureFlags.getSettingSelector())) {
if (client.checkWatchKeys(featureFlags.getSettingSelector(), true)) {
String eventDataInfo = ".appconfig.featureflag/*";

// Only one refresh Event needs to be call to update all of the
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import com.azure.core.http.MatchConditions;
import com.azure.core.http.rest.PagedIterable;
import com.azure.core.http.rest.PagedResponse;
import com.azure.core.util.Context;
import com.azure.data.appconfiguration.ConfigurationClient;
import com.azure.data.appconfiguration.models.ConfigurationSetting;
import com.azure.data.appconfiguration.models.ConfigurationSnapshot;
Expand Down Expand Up @@ -91,11 +92,14 @@ String getEndpoint() {
* @param label String value of the watch key, use \0 for null.
* @return The first returned configuration.
*/
ConfigurationSetting getWatchKey(String key, String label)
ConfigurationSetting getWatchKey(String key, String label, Boolean isRefresh)
throws HttpResponseException {
try {
Context context = new Context("refresh", isRefresh);
ConfigurationSetting selector = new ConfigurationSetting().setKey(key).setLabel(label);
ConfigurationSetting watchKey = NormalizeNull
.normalizeNullLabel(client.getConfigurationSetting(key, label));
.normalizeNullLabel(
client.getConfigurationSettingWithResponse(selector, null, false, context).getValue());
this.failedAttempts = 0;
return watchKey;
} catch (HttpResponseException e) {
Expand All @@ -111,11 +115,12 @@ ConfigurationSetting getWatchKey(String key, String label)
* @param settingSelector Information on which setting to pull. i.e. number of results, key value...
* @return List of Configuration Settings.
*/
List<ConfigurationSetting> listSettings(SettingSelector settingSelector)
List<ConfigurationSetting> listSettings(SettingSelector settingSelector, Boolean isRefresh)
throws HttpResponseException {
List<ConfigurationSetting> configurationSettings = new ArrayList<>();
try {
PagedIterable<ConfigurationSetting> settings = client.listConfigurationSettings(settingSelector);
Context context = new Context("refresh", isRefresh);
PagedIterable<ConfigurationSetting> settings = client.listConfigurationSettings(settingSelector, context);
settings.forEach(setting -> {
configurationSettings.add(NormalizeNull.normalizeNullLabel(setting));
});
Expand All @@ -129,11 +134,12 @@ List<ConfigurationSetting> listSettings(SettingSelector settingSelector)
}
}

FeatureFlags listFeatureFlags(SettingSelector settingSelector) throws HttpResponseException {
FeatureFlags listFeatureFlags(SettingSelector settingSelector, Boolean isRefresh) throws HttpResponseException {
List<ConfigurationSetting> configurationSettings = new ArrayList<>();
List<MatchConditions> checks = new ArrayList<>();
try {
client.listConfigurationSettings(settingSelector).streamByPage().forEach(pagedResponse -> {
Context context = new Context("refresh", isRefresh);
client.listConfigurationSettings(settingSelector, context).streamByPage().forEach(pagedResponse -> {
checks.add(
new MatchConditions().setIfNoneMatch(pagedResponse.getHeaders().getValue(HttpHeaderName.ETAG)));
for (ConfigurationSetting featureFlag : pagedResponse.getValue()) {
Expand Down Expand Up @@ -172,8 +178,9 @@ List<ConfigurationSetting> listSettingSnapshot(String snapshotName) {
}
}

Boolean checkWatchKeys(SettingSelector settingSelector) {
List<PagedResponse<ConfigurationSetting>> results = client.listConfigurationSettings(settingSelector)
Boolean checkWatchKeys(SettingSelector settingSelector, Boolean isRefresh) {
Context context = new Context("refresh", isRefresh);
List<PagedResponse<ConfigurationSetting>> results = client.listConfigurationSettings(settingSelector, context)
.streamByPage().filter(pagedResponse -> pagedResponse.getStatusCode() != 304).toList();
return results.size() > 0;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ public class FeatureFlagClient {
*
*/
public List<FeatureFlags> loadFeatureFlags(AppConfigurationReplicaClient replicaClient, String customKeyFilter,
String[] labelFilter) {
String[] labelFilter, boolean isRefresh) {
List<FeatureFlags> loadedFeatureFlags = new ArrayList<>();

String keyFilter = SELECT_ALL_FEATURE_FLAGS;
Expand All @@ -78,7 +78,7 @@ public List<FeatureFlags> loadFeatureFlags(AppConfigurationReplicaClient replica
for (String label : labels) {
SettingSelector settingSelector = new SettingSelector().setKeyFilter(keyFilter).setLabelFilter(label);

FeatureFlags features = replicaClient.listFeatureFlags(settingSelector);
FeatureFlags features = replicaClient.listFeatureFlags(settingSelector, isRefresh);
loadedFeatureFlags.addAll(proccessFeatureFlags(features, keyFilter));
}
return loadedFeatureFlags;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,12 @@ public enum HostType {
/**
* Host is Container App
*/
CONTAINER_APP("ContainerApp");
CONTAINER_APP("ContainerApp"),

/**
* Host is Service Fabric
*/
SERVICE_FABRIC("ServiceFabric");

private final String text;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,11 @@ public enum RequestTracingConstants {
*/
CONTAINER_APP_ENVIRONMENT_VARIABLE("CONTAINER_APP_NAME"),

/**
* Constant for checking Service Fabric
*/
SERVICE_FABRIC_ENVIRONMENT_VARIABLE("Fabric_NodeName"),

/**
* Constant for tracing the type of request
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,18 @@
// Licensed under the MIT License.
package com.azure.spring.cloud.appconfiguration.config.implementation.http.policy;

import static com.azure.spring.cloud.appconfiguration.config.implementation.AppConfigurationConstants.USER_AGENT_TYPE;

import org.springframework.util.StringUtils;

import com.azure.core.http.HttpHeaderName;
import com.azure.core.http.HttpHeaders;
import com.azure.core.http.HttpPipelineCallContext;
import com.azure.core.http.HttpPipelineNextPolicy;
import com.azure.core.http.HttpResponse;
import com.azure.core.http.policy.HttpPipelinePolicy;
import com.azure.spring.cloud.appconfiguration.config.implementation.RequestTracingConstants;
import com.azure.spring.cloud.appconfiguration.config.implementation.AppConfigurationConstants;

import reactor.core.publisher.Mono;

/**
* HttpPipelinePolicy for connecting to Azure App Configuration.
*/
Expand All @@ -29,8 +30,6 @@ public final class BaseAppConfigurationPolicy implements HttpPipelinePolicy {
public static final String USER_AGENT = String.format("%s/%s", StringUtils.replace(PACKAGE_NAME, " ", ""),
BaseAppConfigurationPolicy.class.getPackage().getImplementationVersion());

static Boolean watchRequests = false;

final TracingInfo tracingInfo;

/**
Expand All @@ -41,22 +40,16 @@ public BaseAppConfigurationPolicy(TracingInfo tracingInfo) {
this.tracingInfo = tracingInfo;
}

@SuppressWarnings("deprecation")
@Override
public Mono<HttpResponse> process(HttpPipelineCallContext context, HttpPipelineNextPolicy next) {
String sdkUserAgent = context.getHttpRequest().getHeaders().get(USER_AGENT_TYPE).getValue();
context.getHttpRequest().getHeaders().set(USER_AGENT_TYPE, USER_AGENT + " " + sdkUserAgent);
context.getHttpRequest().getHeaders().set(RequestTracingConstants.CORRELATION_CONTEXT_HEADER.toString(),
Boolean watchRequests = (Boolean) context.getData("refresh").orElse(false);
HttpHeaders headers = context.getHttpRequest().getHeaders();
String sdkUserAgent = headers.get(HttpHeaderName.USER_AGENT).getValue();
headers.set(HttpHeaderName.USER_AGENT, USER_AGENT + " " + sdkUserAgent);
headers.set(HttpHeaderName.fromString(AppConfigurationConstants.CORRELATION_CONTEXT),
tracingInfo.getValue(watchRequests));

return next.process();
}

/**
* @param watchRequests the watchRequests to set
*/
public static void setWatchRequests(Boolean watchRequests) {
BaseAppConfigurationPolicy.watchRequests = watchRequests;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
import static com.azure.spring.cloud.appconfiguration.config.implementation.AppConfigurationConstants.DEV_ENV_TRACING;
import static com.azure.spring.cloud.appconfiguration.config.implementation.AppConfigurationConstants.KEY_VAULT_CONFIGURED_TRACING;

import org.springframework.util.StringUtils;

import com.azure.core.util.Configuration;
import com.azure.spring.cloud.appconfiguration.config.implementation.HostType;
import com.azure.spring.cloud.appconfiguration.config.implementation.RequestTracingConstants;
Expand All @@ -19,7 +21,7 @@ public class TracingInfo {
private int replicaCount;

private final FeatureFlagTracing featureFlagTracing;

private final Configuration configuration;

public TracingInfo(boolean isDev, boolean isKeyVaultConfigured, int replicaCount, Configuration configuration) {
Expand All @@ -31,7 +33,8 @@ public TracingInfo(boolean isDev, boolean isKeyVaultConfigured, int replicaCount
}

public String getValue(boolean watchRequests) {
String track = configuration.get(RequestTracingConstants.REQUEST_TRACING_DISABLED_ENVIRONMENT_VARIABLE.toString());
String track = configuration
.get(RequestTracingConstants.REQUEST_TRACING_DISABLED_ENVIRONMENT_VARIABLE.toString());
if (track != null && Boolean.valueOf(track)) {
return "";
}
Expand Down Expand Up @@ -60,6 +63,8 @@ public String getValue(boolean watchRequests) {
if (replicaCount > 0) {
sb.append(",").append(RequestTracingConstants.REPLICA_COUNT).append("=").append(replicaCount);
}

sb = getFeatureManagementUsage(sb);

return sb.toString();
}
Expand All @@ -80,10 +85,21 @@ private static String getHostType() {
hostType = HostType.KUBERNETES;
} else if (System.getenv(RequestTracingConstants.CONTAINER_APP_ENVIRONMENT_VARIABLE.toString()) != null) {
hostType = HostType.CONTAINER_APP;
} else if (System.getenv(RequestTracingConstants.SERVICE_FABRIC_ENVIRONMENT_VARIABLE.toString()) != null) {
hostType = HostType.SERVICE_FABRIC;
}

return hostType.toString();
}

private static StringBuilder getFeatureManagementUsage(StringBuilder sb) {
ClassLoader loader = ClassLoader.getSystemClassLoader();
Package ff = loader.getDefinedPackage("com.azure.spring.cloud.feature.management.models");
if (ff != null && StringUtils.hasText(ff.getImplementationVersion())) {
sb.append(",FMSpVer=").append(ff.getImplementationVersion());
}
return sb;
}

/**
* @return the featureFlagTracing
Expand Down
Loading