Skip to content

Commit 12b90f1

Browse files
authored
[AppConfig] Add a customer requested sample - Watch feature (Azure#18780)
* add watch setting refresh sample
1 parent c24325c commit 12b90f1

File tree

2 files changed

+238
-0
lines changed

2 files changed

+238
-0
lines changed
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
package com.azure.data.appconfiguration;
5+
6+
import com.azure.data.appconfiguration.models.ConfigurationSetting;
7+
8+
import java.util.Arrays;
9+
import java.util.List;
10+
import java.util.stream.Collectors;
11+
12+
public class WatchFeature {
13+
/**
14+
* Runs the sample algorithm and demonstrates how to read configuration setting revision history.
15+
*
16+
* @param args Unused. Arguments to the program.
17+
*/
18+
public static void main(String[] args) {
19+
// The connection string value can be obtained by going to your App Configuration instance in the Azure portal
20+
// and navigating to "Access Keys" page under the "Settings" section.
21+
String connectionString = "endpoint={endpoint_value};id={id_value};secret={secret_value}";
22+
23+
// Instantiate a client that will be used to call the service.
24+
ConfigurationClient client = new ConfigurationClientBuilder()
25+
.connectionString(connectionString)
26+
.buildClient();
27+
28+
// Prepare a list of watching settings and update one same setting value to the service.
29+
String prodDBConnectionKey = "prodDBConnection";
30+
String prodDBConnectionLabel = "prodLabel";
31+
32+
// Assume we have a list of watching setting that stored somewhere.
33+
List<ConfigurationSetting> watchingSettings = Arrays.asList(
34+
client.addConfigurationSetting(prodDBConnectionKey, prodDBConnectionLabel, "prodValue"),
35+
client.addConfigurationSetting("stageDBConnection", "stageLabel", "stageValue")
36+
);
37+
38+
System.out.println("Watching settings:");
39+
for (ConfigurationSetting setting : watchingSettings) {
40+
System.out.printf("\tkey=%s, label=%s, value=%s, ETag=%s.%n",
41+
setting.getKey(), setting.getLabel(), setting.getValue(), setting.getETag());
42+
}
43+
44+
// One of the watching settings is been updated by someone in other place.
45+
ConfigurationSetting updatedSetting = client.setConfigurationSetting(
46+
prodDBConnectionKey, prodDBConnectionLabel, "updatedProdValue");
47+
System.out.println("Updated settings:");
48+
System.out.printf("\tkey=%s, label=%s, value=%s, ETag=%s.%n",
49+
updatedSetting.getKey(), updatedSetting.getLabel(), updatedSetting.getValue(), updatedSetting.getETag());
50+
51+
// Updates the watching settings if needed, and only returns a list of updated settings.
52+
List<ConfigurationSetting> refreshedSettings = refresh(client, watchingSettings);
53+
54+
System.out.println("Refreshed settings:");
55+
for (ConfigurationSetting setting : refreshedSettings) {
56+
System.out.printf("\tkey=%s, label=%s, value=%s, ETag=%s.%n",
57+
setting.getKey(), setting.getLabel(), setting.getValue(), setting.getETag());
58+
}
59+
60+
// Cleaning up after ourselves by deleting the values.
61+
System.out.println("Deleting settings:");
62+
watchingSettings.forEach(setting -> {
63+
client.deleteConfigurationSetting(setting.getKey(), setting.getLabel());
64+
System.out.printf("\tkey: %s, value: %s.%n", setting.getKey(), setting.getValue());
65+
});
66+
}
67+
68+
/**
69+
* A refresh method that runs every day to update settings and returns a updated settings.
70+
*
71+
* @param client a configuration client.
72+
* @param watchSettings a list of settings in the watching store.
73+
*
74+
* @return a list of updated settings that doesn't match previous ETag value.
75+
*/
76+
private static List<ConfigurationSetting> refresh(ConfigurationClient client,
77+
List<ConfigurationSetting> watchSettings) {
78+
return watchSettings
79+
.stream()
80+
.filter(setting -> {
81+
ConfigurationSetting retrievedSetting = client.getConfigurationSetting(setting.getKey(),
82+
setting.getLabel());
83+
String latestETag = retrievedSetting.getETag();
84+
String watchingETag = setting.getETag();
85+
if (!latestETag.equals(watchingETag)) {
86+
System.out.printf(
87+
"Some keys in watching key store matching the key [%s] and label [%s] is updated, "
88+
+ "preview ETag value [%s] not equals to current value [%s].%n",
89+
retrievedSetting.getKey(), retrievedSetting.getLabel(), watchingETag, latestETag);
90+
setting.setETag(latestETag).setValue(retrievedSetting.getValue());
91+
return true;
92+
}
93+
return false;
94+
})
95+
.collect(Collectors.toList());
96+
}
97+
}
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
package com.azure.data.appconfiguration;
5+
6+
import com.azure.data.appconfiguration.models.ConfigurationSetting;
7+
import com.azure.data.appconfiguration.models.SettingSelector;
8+
import reactor.core.publisher.Flux;
9+
10+
import java.util.ArrayList;
11+
import java.util.List;
12+
import java.util.concurrent.TimeUnit;
13+
import java.util.stream.Collectors;
14+
import java.util.stream.Stream;
15+
16+
public class WatchFeatureAsync {
17+
/**
18+
* Runs the sample algorithm and demonstrates how to read configuration setting revision history.
19+
*
20+
* @param args Unused. Arguments to the program.
21+
*/
22+
public static void main(String[] args) throws InterruptedException {
23+
// The connection string value can be obtained by going to your App Configuration instance in the Azure portal
24+
// and navigating to "Access Keys" page under the "Settings" section.
25+
String connectionString = "endpoint={endpoint_value};id={id_value};secret={secret_value}";
26+
27+
// Instantiate a client that will be used to call the service.
28+
ConfigurationAsyncClient client = new ConfigurationClientBuilder()
29+
.connectionString(connectionString)
30+
.buildAsyncClient();
31+
32+
// Prepare a list of watching settings and update one same setting value to the service.
33+
String prodDBConnectionKey = "prodDBConnection";
34+
String prodDBConnectionLabel = "prodLabel";
35+
String updatedProdDBConnectionValue = "updateProdValue";
36+
37+
// Assume we have a list of watching setting that stored somewhere.
38+
List<ConfigurationSetting> watchingSettings = new ArrayList<>();
39+
Flux.concat(
40+
client.addConfigurationSetting(prodDBConnectionKey, prodDBConnectionLabel, "prodValue"),
41+
client.addConfigurationSetting("stageDBConnection", "stageLabel", "stageValue"))
42+
.then(client.listConfigurationSettings(new SettingSelector().setKeyFilter("*")).collectList())
43+
.subscribe(
44+
settings -> watchingSettings.addAll(settings),
45+
error -> System.err.printf("There was an error while adding the settings: %s.%n", error),
46+
() -> System.out.println("Add settings completed.")
47+
);
48+
49+
// The .subscribe() creation and assignment is not a blocking call. For the purpose of this example, we sleep
50+
// the thread so the program does not end before the send operation is complete. Using .block() instead of
51+
// .subscribe() will turn this into a synchronous call.
52+
TimeUnit.MILLISECONDS.sleep(1000);
53+
54+
System.out.println("Watching settings:");
55+
for (ConfigurationSetting setting : watchingSettings) {
56+
System.out.printf("\tWatching key=%s, label=%s, value=%s, ETag=%s.%n",
57+
setting.getKey(), setting.getLabel(), setting.getValue(), setting.getETag());
58+
}
59+
TimeUnit.MILLISECONDS.sleep(1000);
60+
61+
// One of the watching settings is been updated by someone in other place.
62+
client.setConfigurationSetting(prodDBConnectionKey, prodDBConnectionLabel, updatedProdDBConnectionValue)
63+
.subscribe(
64+
updatedSetting -> {
65+
System.out.println("Updated settings:");
66+
System.out.printf("\tUpdated key=%s, label=%s, value=%s, ETag=%s.%n",
67+
updatedSetting.getKey(), updatedSetting.getLabel(), updatedSetting.getValue(),
68+
updatedSetting.getETag());
69+
},
70+
error -> System.err.printf("There was an error while updating the setting: %s.%n", error),
71+
() -> System.out.printf("Update setting completed, key=%s, label=%s, value=%s.%n",
72+
prodDBConnectionKey, prodDBConnectionLabel, updatedProdDBConnectionValue));
73+
TimeUnit.MILLISECONDS.sleep(1000);
74+
75+
// Updates the watching settings if needed, and only returns a list of updated settings.
76+
List<ConfigurationSetting> refreshedSettings = refresh(client, watchingSettings);
77+
System.out.println("Refreshed settings:");
78+
for (ConfigurationSetting setting : refreshedSettings) {
79+
System.out.printf("\tRefreshed key=%s, label=%s, value=%s, ETag=%s.%n",
80+
setting.getKey(), setting.getLabel(), setting.getValue(), setting.getETag());
81+
}
82+
TimeUnit.MILLISECONDS.sleep(1000);
83+
84+
// Cleaning up after ourselves by deleting the values.
85+
System.out.println("Deleting settings:");
86+
Stream<ConfigurationSetting> stream = watchingSettings == null ? Stream.empty() : watchingSettings.stream();
87+
Flux.merge(stream.map(setting -> {
88+
System.out.printf("\tDeleting key: %s, value: %s.%n", setting.getKey(), setting.getValue());
89+
return client.deleteConfigurationSettingWithResponse(setting, false);
90+
}).collect(Collectors.toList())).blockLast();
91+
}
92+
93+
/**
94+
* A refresh method that runs every day to update settings and returns a updated settings.
95+
*
96+
* @param client a configuration client.
97+
* @param watchSettings a list of settings in the watching store.
98+
*
99+
* @return a list of updated settings that doesn't match previous ETag value.
100+
*/
101+
private static List<ConfigurationSetting> refresh(ConfigurationAsyncClient client,
102+
List<ConfigurationSetting> watchSettings) {
103+
return watchSettings
104+
.stream()
105+
.filter(setting -> {
106+
final boolean[] isUpdated = new boolean[1];
107+
String key = setting.getKey();
108+
String label = setting.getLabel();
109+
client.getConfigurationSetting(key, label)
110+
.subscribe(
111+
retrievedSetting -> {
112+
String latestETag = retrievedSetting.getETag();
113+
String watchingETag = setting.getETag();
114+
if (!latestETag.equals(watchingETag)) {
115+
System.out.printf(
116+
"Some keys in watching key store matching the key [%s] and label [%s] is "
117+
+ "updated, preview ETag value [%s] not equals to current value [%s].%n",
118+
retrievedSetting.getKey(), retrievedSetting.getLabel(), watchingETag,
119+
latestETag);
120+
setting.setETag(latestETag).setValue(retrievedSetting.getValue());
121+
isUpdated[0] = true;
122+
}
123+
},
124+
error -> System.err.printf("There was an error while retrieving the setting: %s.%n",
125+
error),
126+
() -> System.out.printf("Retrieve setting completed, key=%s, label=%s.%n", key, label));
127+
128+
// The .subscribe() creation and assignment is not a blocking call. For the purpose of this
129+
// example, we sleep the thread so the program does not end before the send operation is
130+
// complete. Using .block() instead of .subscribe() will turn this into a synchronous call.
131+
try {
132+
TimeUnit.MILLISECONDS.sleep(1000);
133+
} catch (InterruptedException e) {
134+
e.printStackTrace();
135+
}
136+
137+
return isUpdated[0];
138+
})
139+
.collect(Collectors.toList());
140+
}
141+
}

0 commit comments

Comments
 (0)