How-To: Manage configuration from a store

Learn how to get application configuration and subscribe for changes

This example uses the Redis configuration store component to demonstrate how to retrieve a configuration item.

Note

This API is currently in Alpha state and only available on gRPC. An HTTP1.1 supported version with this URL syntax /v1.0/configuration will be available before the API is certified into Stable state.

Diagram showing get configuration of example service

Create a configuration item in store

Create a configuration item in a supported configuration store. This can be a simple key-value item, with any key of your choice. As mentioned earlier, this example uses the Redis configuration store component.

Run Redis with Docker

  1. docker run --name my-redis -p 6379:6379 -d redis:6

Save an item

Using the Redis CLI, connect to the Redis instance:

  1. redis-cli -p 6379

Save a configuration item:

  1. MSET orderId1 "101||1" orderId2 "102||1"

Configure a Dapr configuration store

Save the following component file to the default components folder on your machine. You can use this as the Dapr component YAML:

  • For Kubernetes using kubectl.
  • When running with the Dapr CLI.

Note

Since the Redis configuration component has identical metadata to the Redis statestore.yaml component, you can simply copy/change the Redis state store component type if you already have a Redis statestore.yaml.

  1. apiVersion: dapr.io/v1alpha1
  2. kind: Component
  3. metadata:
  4. name: configstore
  5. spec:
  6. type: configuration.redis
  7. metadata:
  8. - name: redisHost
  9. value: localhost:6379
  10. - name: redisPassword
  11. value: <PASSWORD>

Retrieve Configuration Items

Get configuration items using Dapr SDKs

  1. //dependencies
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Threading.Tasks;
  5. using Dapr.Client;
  6. //code
  7. namespace ConfigurationApi
  8. {
  9. public class Program
  10. {
  11. private static readonly string CONFIG_STORE_NAME = "configstore";
  12. [Obsolete]
  13. public static async Task Main(string[] args)
  14. {
  15. using var client = new DaprClientBuilder().Build();
  16. var configuration = await client.GetConfiguration(CONFIG_STORE_NAME, new List<string>() { "orderId1", "orderId2" });
  17. Console.WriteLine($"Got key=\n{configuration[0].Key} -> {configuration[0].Value}\n{configuration[1].Key} -> {configuration[1].Value}");
  18. }
  19. }
  20. }
  1. //dependencies
  2. import io.dapr.client.DaprClientBuilder;
  3. import io.dapr.client.DaprPreviewClient;
  4. import io.dapr.client.domain.ConfigurationItem;
  5. import io.dapr.client.domain.GetConfigurationRequest;
  6. import io.dapr.client.domain.SubscribeConfigurationRequest;
  7. import reactor.core.publisher.Flux;
  8. import reactor.core.publisher.Mono;
  9. //code
  10. private static final String CONFIG_STORE_NAME = "configstore";
  11. public static void main(String[] args) throws Exception {
  12. try (DaprPreviewClient client = (new DaprClientBuilder()).buildPreviewClient()) {
  13. List<String> keys = new ArrayList<>();
  14. keys.add("orderId1");
  15. keys.add("orderId2");
  16. GetConfigurationRequest req = new GetConfigurationRequest(CONFIG_STORE_NAME, keys);
  17. try {
  18. Mono<List<ConfigurationItem>> items = client.getConfiguration(req);
  19. items.block().forEach(ConfigurationClient::print);
  20. } catch (Exception ex) {
  21. System.out.println(ex.getMessage());
  22. }
  23. }
  24. }
  1. #dependencies
  2. from dapr.clients import DaprClient
  3. #code
  4. with DaprClient() as d:
  5. CONFIG_STORE_NAME = 'configstore'
  6. keys = ['orderId1', 'orderId2']
  7. #Startup time for dapr
  8. d.wait(20)
  9. configuration = d.get_configuration(store_name=CONFIG_STORE_NAME, keys=[keys], config_metadata={})
  10. print(f"Got key={configuration.items[0].key} value={configuration.items[0].value} version={configuration.items[0].version}")

Get configuration items using gRPC API

Using your favorite language, create a Dapr gRPC client from the Dapr proto. The following examples show Java, C#, Python and Javascript clients.

  1. Dapr.ServiceBlockingStub stub = Dapr.newBlockingStub(channel);
  2. stub.GetConfigurationAlpha1(new GetConfigurationRequest{ StoreName = "redisconfigstore", Keys = new String[]{"myconfig"} });
  1. var call = client.GetConfigurationAlpha1(new GetConfigurationRequest { StoreName = "redisconfigstore", Keys = new String[]{"myconfig"} });
  1. response = stub.GetConfigurationAlpha1(request={ StoreName: 'redisconfigstore', Keys = ['myconfig'] })
  1. client.GetConfigurationAlpha1({ StoreName: 'redisconfigstore', Keys = ['myconfig'] })

Watch configuration items using Dapr SDKs

  1. [Obsolete("Configuration API is an Alpha API. Obsolete will be removed when the API is no longer Alpha")]
  2. public static void Main(string[] args)
  3. {
  4. CreateHostBuilder(args).Build().Run();
  5. }
  6. public static IHostBuilder CreateHostBuilder(string[] args)
  7. {
  8. var client = new DaprClientBuilder().Build();
  9. return Host.CreateDefaultBuilder(args)
  10. .ConfigureAppConfiguration(config =>
  11. {
  12. // Get the initial value from the configuration component.
  13. config.AddDaprConfigurationStore("redisconfig", new List<string>() { "withdrawVersion" }, client, TimeSpan.FromSeconds(20));
  14. // Watch the keys in the configuration component and update it in local configurations.
  15. config.AddStreamingDaprConfigurationStore("redisconfig", new List<string>() { "withdrawVersion", "source" }, client, TimeSpan.FromSeconds(20));
  16. })
  17. .ConfigureWebHostDefaults(webBuilder =>
  18. {
  19. webBuilder.UseStartup<Startup>();
  20. });
  21. }
  1. public IDictionary<string, string> Data { get; set; } = new Dictionary<string, string>();
  2. public string Id { get; set; } = string.Empty;
  3. public async Task WatchConfiguration(DaprClient daprClient, string store, IReadOnlyList<string> keys, Dictionary<string, string> metadata, CancellationToken token = default)
  4. {
  5. // Initialize the gRPC Stream that will provide configuration updates.
  6. var subscribeConfigurationResponse = await daprClient.SubscribeConfiguration(store, keys, metadata, token);
  7. // The response contains a data source which is an IAsyncEnumerable, so it can be iterated through via an awaited foreach.
  8. await foreach (var items in subscribeConfigurationResponse.Source.WithCancellation(token))
  9. {
  10. // Each iteration from the stream can contain all the keys that were queried for, so it must be individually iterated through.
  11. var data = new Dictionary<string, string>(Data);
  12. foreach (var item in items)
  13. {
  14. // The Id in the response is used to unsubscribe.
  15. Id = subscribeConfigurationResponse.Id;
  16. data[item.Key] = item.Value;
  17. }
  18. Data = data;
  19. }
  20. }

Watch configuration items using gRPC API

Create a Dapr gRPC client from the Dapr proto using your preferred language. Use the SubscribeConfigurationAlpha1 proto method on your client stub to start subscribing to events. The method accepts the following request object:

  1. message SubscribeConfigurationRequest {
  2. // The name of configuration store.
  3. string store_name = 1;
  4. // Optional. The key of the configuration item to fetch.
  5. // If set, only query for the specified configuration items.
  6. // Empty list means fetch all.
  7. repeated string keys = 2;
  8. // The metadata which will be sent to configuration store components.
  9. map<string,string> metadata = 3;
  10. }

Using this method, you can subscribe to changes in specific keys for a given configuration store. gRPC streaming varies widely based on language - see the gRPC examples here for usage.

Below are the examples in sdks:

  1. #dependencies
  2. import asyncio
  3. from dapr.clients import DaprClient
  4. #code
  5. async def executeConfiguration():
  6. with DaprClient() as d:
  7. CONFIG_STORE_NAME = 'configstore'
  8. key = 'orderId'
  9. # Subscribe to configuration by key.
  10. configuration = await d.subscribe_configuration(store_name=CONFIG_STORE_NAME, keys=[key], config_metadata={})
  11. if configuration != None:
  12. items = configuration.get_items()
  13. for item in items:
  14. print(f"Subscribe key={item.key} value={item.value} version={item.version}", flush=True)
  15. else:
  16. print("Nothing yet")
  17. asyncio.run(executeConfiguration())
  1. dapr run --app-id orderprocessing --components-path components/ -- python3 OrderProcessingService.py

Stop watching configuration items

After you’ve subscribed to watch configuration items, the gRPC-server stream starts. Since this stream thread does not close itself, you have to explicitly call the UnSubscribeConfigurationRequest API to unsubscribe. This method accepts the following request object:

  1. // UnSubscribeConfigurationRequest is the message to stop watching the key-value configuration.
  2. message UnSubscribeConfigurationRequest {
  3. // The name of configuration store.
  4. string store_name = 1;
  5. // Optional. The keys of the configuration item to stop watching.
  6. // Store_name and keys should match previous SubscribeConfigurationRequest's keys and store_name.
  7. // Once invoked, the subscription that is watching update for the key-value event is stopped
  8. repeated string keys = 2;
  9. }

Using this unsubscribe method, you can stop watching configuration update events. Dapr locates the subscription stream based on the store_name and any optional keys supplied and closes it.

Next steps

Last modified August 11, 2022: redis 6 update (#2718) (08f2cf27)