mirror of https://github.com/dapr/docs.git
Update configuration api (#3410)
* updating alpha1 endpoint to stable Signed-off-by: Shivam Kumar <shivamkm07@gmail.com> * lowercaing table name in postgres Signed-off-by: Shivam Kumar <shivamkm07@gmail.com> * updating redis metadata Signed-off-by: Shivam Kumar <shivamkm07@gmail.com> * updating redis and postgres to stable Signed-off-by: Shivam Kumar <shivamkm07@gmail.com> * updating configuration manage: wip Signed-off-by: Shivam Kumar <shivamkm07@gmail.com> * Apply suggestions from code review Co-authored-by: Mark Fussell <markfussell@gmail.com> Co-authored-by: Hannah Hunter <94493363+hhunter-ms@users.noreply.github.com> Signed-off-by: Shivam Kumar <shivamkm07@gmail.com> * adding demo link Signed-off-by: Shivam Kumar <shivamkm07@gmail.com> * updating sdk codes Signed-off-by: Shivam Kumar <shivamkm07@gmail.com> * adding java sdk subscribe Signed-off-by: Shivam Kumar <shivamkm07@gmail.com> * adding javascript sdk subscribe Signed-off-by: Shivam Kumar <shivamkm07@gmail.com> * adding sdk unsubscribe Signed-off-by: Shivam Kumar <shivamkm07@gmail.com> * adding quotes Signed-off-by: Shivam Kumar <shivamkm07@gmail.com> * Update howto-manage-configuration.md Updating a small grammar change --------- Signed-off-by: Shivam Kumar <shivamkm07@gmail.com> Co-authored-by: Mark Fussell <markfussell@gmail.com> Co-authored-by: Hannah Hunter <94493363+hhunter-ms@users.noreply.github.com>
This commit is contained in:
parent
46f9f4d06d
commit
5696e3ccdf
|
@ -27,6 +27,6 @@ The following are the building blocks provided by Dapr:
|
|||
| [**Actors**]({{< ref "actors-overview.md" >}}) | `/v1.0/actors` | An actor is an isolated, independent unit of compute and state with single-threaded execution. Dapr provides an actor implementation based on the virtual actor pattern which provides a single-threaded programming model and where actors are garbage collected when not in use.
|
||||
| [**Observability**]({{< ref "observability-concept.md" >}}) | `N/A` | Dapr system components and runtime emit metrics, logs, and traces to debug, operate and monitor Dapr system services, components and user applications.
|
||||
| [**Secrets**]({{< ref "secrets-overview.md" >}}) | `/v1.0/secrets` | Dapr provides a secrets building block API and integrates with secret stores such as public cloud stores, local stores and Kubernetes to store the secrets. Services can call the secrets API to retrieve secrets, for example to get a connection string to a database.
|
||||
| [**Configuration**]({{< ref "configuration-api-overview.md" >}}) | `/v1.0-alpha1/configuration` | The Configuration API enables you to retrieve and subscribe to application configuration items for supported configuration stores. This enables an application to retrieve specific configuration information, for example, at start up or when configuration changes are made in the store.
|
||||
| [**Configuration**]({{< ref "configuration-api-overview.md" >}}) | `/v1.0/configuration` | The Configuration API enables you to retrieve and subscribe to application configuration items for supported configuration stores. This enables an application to retrieve specific configuration information, for example, at start up or when configuration changes are made in the store.
|
||||
| [**Distributed lock**]({{< ref "distributed-lock-api-overview.md" >}}) | `/v1.0-alpha1/lock` | The distributed lock API enables you to take a lock on a resource so that multiple instances of an application can access the resource without conflicts and provide consistency guarantees.
|
||||
| [**Workflows**]({{< ref "workflow-overview.md" >}}) | `/v1.0-alpha1/workflow` | The Workflow API enables you to define long running, persistent processes or data flows that span multiple microservices using Dapr workflows or workflow components. The Workflow API can be combined with other Dapr API building blocks. For example, a workflow can call another service with service invocation or retrieve secrets, providing flexibility and portability.
|
|
@ -40,6 +40,11 @@ Want to put the Dapr configuration API to the test? Walk through the following q
|
|||
|
||||
Want to skip the quickstarts? Not a problem. You can try out the configuration building block directly in your application to read and manage configuration data. After [Dapr is installed]({{< ref "getting-started/_index.md" >}}), you can begin using the configuration API starting with [the configuration how-to guide]({{< ref howto-manage-configuration.md >}}).
|
||||
|
||||
## Watch the demo
|
||||
|
||||
Watch [this demo of using the Dapr Configuration building block](https://youtu.be/tNq-n1XQuLA?t=496)
|
||||
|
||||
<iframe width="560" height="315" src="https://www.youtube-nocookie.com/embed/tNq-n1XQuLA?start=496" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>
|
||||
|
||||
## Next steps
|
||||
Follow these guides on:
|
||||
|
|
|
@ -67,9 +67,11 @@ spec:
|
|||
```
|
||||
|
||||
## Retrieve Configuration Items
|
||||
### Get configuration items using Dapr SDKs
|
||||
### Get configuration items
|
||||
|
||||
{{< tabs ".NET" Java Python>}}
|
||||
The following example shows how to get a saved configuration item using the Dapr Configuration API.
|
||||
|
||||
{{< tabs ".NET" Java Python Go Javascript "HTTP API (BASH)" "HTTP API (Powershell)">}}
|
||||
|
||||
{{% codetab %}}
|
||||
|
||||
|
@ -87,7 +89,6 @@ namespace ConfigurationApi
|
|||
{
|
||||
private static readonly string CONFIG_STORE_NAME = "configstore";
|
||||
|
||||
[Obsolete]
|
||||
public static async Task Main(string[] args)
|
||||
{
|
||||
using var client = new DaprClientBuilder().Build();
|
||||
|
@ -105,7 +106,7 @@ namespace ConfigurationApi
|
|||
```java
|
||||
//dependencies
|
||||
import io.dapr.client.DaprClientBuilder;
|
||||
import io.dapr.client.DaprPreviewClient;
|
||||
import io.dapr.client.DaprClient;
|
||||
import io.dapr.client.domain.ConfigurationItem;
|
||||
import io.dapr.client.domain.GetConfigurationRequest;
|
||||
import io.dapr.client.domain.SubscribeConfigurationRequest;
|
||||
|
@ -116,7 +117,7 @@ import reactor.core.publisher.Mono;
|
|||
private static final String CONFIG_STORE_NAME = "configstore";
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
try (DaprPreviewClient client = (new DaprClientBuilder()).buildPreviewClient()) {
|
||||
try (DaprClient client = (new DaprClientBuilder()).build()) {
|
||||
List<String> keys = new ArrayList<>();
|
||||
keys.add("orderId1");
|
||||
keys.add("orderId2");
|
||||
|
@ -150,79 +151,31 @@ with DaprClient() as d:
|
|||
|
||||
{{% /codetab %}}
|
||||
|
||||
{{< /tabs >}}
|
||||
|
||||
### Get configuration items using gRPC API
|
||||
|
||||
Using your [favorite language](https://grpc.io/docs/languages/), create a Dapr gRPC client from the [Dapr proto](https://github.com/dapr/dapr/blob/master/dapr/proto/runtime/v1/dapr.proto). The following examples show Java, C#, Python and Javascript clients.
|
||||
|
||||
{{< tabs Java Dotnet Python Javascript >}}
|
||||
|
||||
{{% codetab %}}
|
||||
|
||||
```java
|
||||
```go
|
||||
package main
|
||||
|
||||
Dapr.ServiceBlockingStub stub = Dapr.newBlockingStub(channel);
|
||||
stub.GetConfigurationAlpha1(new GetConfigurationRequest{ StoreName = "redisconfigstore", Keys = new String[]{"myconfig"} });
|
||||
```
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
{{% /codetab %}}
|
||||
dapr "github.com/dapr/go-sdk/client"
|
||||
)
|
||||
|
||||
{{% codetab %}}
|
||||
|
||||
```csharp
|
||||
|
||||
var call = client.GetConfigurationAlpha1(new GetConfigurationRequest { StoreName = "redisconfigstore", Keys = new String[]{"myconfig"} });
|
||||
```
|
||||
|
||||
{{% /codetab %}}
|
||||
|
||||
{{% codetab %}}
|
||||
|
||||
```python
|
||||
response = stub.GetConfigurationAlpha1(request={ StoreName: 'redisconfigstore', Keys = ['myconfig'] })
|
||||
```
|
||||
|
||||
{{% /codetab %}}
|
||||
|
||||
{{% codetab %}}
|
||||
|
||||
```javascript
|
||||
client.GetConfigurationAlpha1({ StoreName: 'redisconfigstore', Keys = ['myconfig'] })
|
||||
```
|
||||
|
||||
{{% /codetab %}}
|
||||
|
||||
{{< /tabs >}}
|
||||
|
||||
### Watch configuration items using Dapr SDKs
|
||||
|
||||
{{< tabs "Dotnet Extension" "Dotnet Client">}}
|
||||
{{% codetab %}}
|
||||
|
||||
```csharp
|
||||
[Obsolete("Configuration API is an Alpha API. Obsolete will be removed when the API is no longer Alpha")]
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
CreateHostBuilder(args).Build().Run();
|
||||
}
|
||||
|
||||
public static IHostBuilder CreateHostBuilder(string[] args)
|
||||
{
|
||||
var client = new DaprClientBuilder().Build();
|
||||
return Host.CreateDefaultBuilder(args)
|
||||
.ConfigureAppConfiguration(config =>
|
||||
{
|
||||
// Get the initial value from the configuration component.
|
||||
config.AddDaprConfigurationStore("redisconfig", new List<string>() { "withdrawVersion" }, client, TimeSpan.FromSeconds(20));
|
||||
|
||||
// Watch the keys in the configuration component and update it in local configurations.
|
||||
config.AddStreamingDaprConfigurationStore("redisconfig", new List<string>() { "withdrawVersion", "source" }, client, TimeSpan.FromSeconds(20));
|
||||
})
|
||||
.ConfigureWebHostDefaults(webBuilder =>
|
||||
{
|
||||
webBuilder.UseStartup<Startup>();
|
||||
});
|
||||
func main() {
|
||||
ctx := context.Background()
|
||||
client, err := dapr.NewClient()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
items, err := client.GetConfigurationItems(ctx, "configstore", ["orderId1","orderId2"])
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
for key, item := range items {
|
||||
fmt.Printf("get config: key = %s value = %s version = %s",key,(*item).Value, (*item).Version)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -230,106 +183,502 @@ public static IHostBuilder CreateHostBuilder(string[] args)
|
|||
|
||||
{{% codetab %}}
|
||||
|
||||
```js
|
||||
import { CommunicationProtocolEnum, DaprClient } from "@dapr/dapr";
|
||||
|
||||
// JS SDK does not support Configuration API over HTTP protocol yet
|
||||
const protocol = CommunicationProtocolEnum.GRPC;
|
||||
const host = process.env.DAPR_HOST ?? "localhost";
|
||||
const port = process.env.DAPR_GRPC_PORT ?? 3500;
|
||||
|
||||
const DAPR_CONFIGURATION_STORE = "configstore";
|
||||
const CONFIGURATION_ITEMS = ["orderId1", "orderId2"];
|
||||
|
||||
async function main() {
|
||||
const client = new DaprClient(host, port, protocol);
|
||||
// Get config items from the config store
|
||||
try {
|
||||
const config = await client.configuration.get(DAPR_CONFIGURATION_STORE, CONFIGURATION_ITEMS);
|
||||
Object.keys(config.items).forEach((key) => {
|
||||
console.log("Configuration for " + key + ":", JSON.stringify(config.items[key]));
|
||||
});
|
||||
} catch (error) {
|
||||
console.log("Could not get config item, err:" + error);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
main().catch((e) => console.error(e));
|
||||
```
|
||||
|
||||
{{% /codetab %}}
|
||||
|
||||
{{% codetab %}}
|
||||
|
||||
Launch a dapr sidecar:
|
||||
|
||||
```bash
|
||||
dapr run --app-id orderprocessing --dapr-http-port 3601
|
||||
```
|
||||
|
||||
In a separate terminal, get the configuration item saved earlier:
|
||||
|
||||
```bash
|
||||
curl http://localhost:3601/v1.0/configuration/configstore?key=orderId1
|
||||
```
|
||||
|
||||
{{% /codetab %}}
|
||||
|
||||
{{% codetab %}}
|
||||
|
||||
Launch a Dapr sidecar:
|
||||
|
||||
```bash
|
||||
dapr run --app-id orderprocessing --dapr-http-port 3601
|
||||
```
|
||||
|
||||
In a separate terminal, get the configuration item saved earlier:
|
||||
|
||||
```powershell
|
||||
Invoke-RestMethod -Uri 'http://localhost:3601/v1.0/configuration/configstore?key=orderId1'
|
||||
```
|
||||
|
||||
{{% /codetab %}}
|
||||
|
||||
{{< /tabs >}}
|
||||
|
||||
|
||||
### Subscribe to configuration item updates
|
||||
|
||||
Below are code examples that leverage SDKs to subscribe to keys `[orderId1, orderId2]` using `configstore` store component.
|
||||
|
||||
{{< tabs ".NET" "ASP.NET Core" Java Python Go Javascript>}}
|
||||
|
||||
{{% codetab %}}
|
||||
|
||||
```csharp
|
||||
public IDictionary<string, string> Data { get; set; } = new Dictionary<string, string>();
|
||||
public string Id { get; set; } = string.Empty;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Dapr.Client;
|
||||
|
||||
public async Task WatchConfiguration(DaprClient daprClient, string store, IReadOnlyList<string> keys, Dictionary<string, string> metadata, CancellationToken token = default)
|
||||
const string DAPR_CONFIGURATION_STORE = "configstore";
|
||||
var CONFIGURATION_KEYS = new List<string> { "orderId1", "orderId2" };
|
||||
var client = new DaprClientBuilder().Build();
|
||||
|
||||
// Subscribe for configuration changes
|
||||
SubscribeConfigurationResponse subscribe = await client.SubscribeConfiguration(DAPR_CONFIGURATION_STORE, CONFIGURATION_ITEMS);
|
||||
|
||||
// Print configuration changes
|
||||
await foreach (var items in subscribe.Source)
|
||||
{
|
||||
// Initialize the gRPC Stream that will provide configuration updates.
|
||||
var subscribeConfigurationResponse = await daprClient.SubscribeConfiguration(store, keys, metadata, token);
|
||||
// First invocation when app subscribes to config changes only returns subscription id
|
||||
if (items.Keys.Count == 0)
|
||||
{
|
||||
Console.WriteLine("App subscribed to config changes with subscription id: " + subscribe.Id);
|
||||
subscriptionId = subscribe.Id;
|
||||
continue;
|
||||
}
|
||||
var cfg = System.Text.Json.JsonSerializer.Serialize(items);
|
||||
Console.WriteLine("Configuration update " + cfg);
|
||||
}
|
||||
```
|
||||
|
||||
// The response contains a data source which is an IAsyncEnumerable, so it can be iterated through via an awaited foreach.
|
||||
await foreach (var items in subscribeConfigurationResponse.Source.WithCancellation(token))
|
||||
Navigate to the directory containing the above code, then run the following command to launch both a Dapr sidecar and the subscriber application:
|
||||
|
||||
```bash
|
||||
dapr run --app-id orderprocessing -- dotnet run
|
||||
```
|
||||
|
||||
{{% /codetab %}}
|
||||
|
||||
{{% codetab %}}
|
||||
|
||||
```csharp
|
||||
using System;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Dapr.Client;
|
||||
using Dapr.Extensions.Configuration;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
|
||||
namespace ConfigurationApi
|
||||
{
|
||||
public class Program
|
||||
{
|
||||
// Each iteration from the stream can contain all the keys that were queried for, so it must be individually iterated through.
|
||||
var data = new Dictionary<string, string>(Data);
|
||||
foreach (var item in items)
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
// The Id in the response is used to unsubscribe.
|
||||
Id = subscribeConfigurationResponse.Id;
|
||||
data[item.Key] = item.Value;
|
||||
Console.WriteLine("Starting application.");
|
||||
CreateHostBuilder(args).Build().Run();
|
||||
Console.WriteLine("Closing application.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates WebHost Builder.
|
||||
/// </summary>
|
||||
/// <param name="args">Arguments.</param>
|
||||
/// <returns>Returns IHostbuilder.</returns>
|
||||
public static IHostBuilder CreateHostBuilder(string[] args)
|
||||
{
|
||||
var client = new DaprClientBuilder().Build();
|
||||
return Host.CreateDefaultBuilder(args)
|
||||
.ConfigureAppConfiguration(config =>
|
||||
{
|
||||
// Get the initial value and continue to watch it for changes.
|
||||
config.AddDaprConfigurationStore("configstore", new List<string>() { "orderId1","orderId2" }, client, TimeSpan.FromSeconds(20));
|
||||
config.AddStreamingDaprConfigurationStore("configstore", new List<string>() { "orderId1","orderId2" }, client, TimeSpan.FromSeconds(20));
|
||||
|
||||
})
|
||||
.ConfigureWebHostDefaults(webBuilder =>
|
||||
{
|
||||
webBuilder.UseStartup<Startup>();
|
||||
});
|
||||
}
|
||||
Data = data;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Navigate to the directory containing the above code, then run the following command to launch both a Dapr sidecar and the subscriber application:
|
||||
|
||||
```bash
|
||||
dapr run --app-id orderprocessing -- dotnet run
|
||||
```
|
||||
|
||||
{{% /codetab %}}
|
||||
{{< /tabs >}}
|
||||
|
||||
### Watch configuration items using gRPC API
|
||||
{{% codetab %}}
|
||||
|
||||
Create a Dapr gRPC client from the [Dapr proto](https://github.com/dapr/dapr/blob/master/dapr/proto/runtime/v1/dapr.proto) using your [preferred language](https://grpc.io/docs/languages/). Use the `SubscribeConfigurationAlpha1` proto method on your client stub to start subscribing to events. The method accepts the following request object:
|
||||
```java
|
||||
import io.dapr.client.DaprClientBuilder;
|
||||
import io.dapr.client.DaprClient;
|
||||
import io.dapr.client.domain.ConfigurationItem;
|
||||
import io.dapr.client.domain.GetConfigurationRequest;
|
||||
import io.dapr.client.domain.SubscribeConfigurationRequest;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
```proto
|
||||
message SubscribeConfigurationRequest {
|
||||
// The name of configuration store.
|
||||
string store_name = 1;
|
||||
//code
|
||||
private static final String CONFIG_STORE_NAME = "configstore";
|
||||
private static String subscriptionId = null;
|
||||
|
||||
// Optional. The key of the configuration item to fetch.
|
||||
// If set, only query for the specified configuration items.
|
||||
// Empty list means fetch all.
|
||||
repeated string keys = 2;
|
||||
public static void main(String[] args) throws Exception {
|
||||
try (DaprClient client = (new DaprClientBuilder()).build()) {
|
||||
// Subscribe for config changes
|
||||
List<String> keys = new ArrayList<>();
|
||||
keys.add("orderId1");
|
||||
keys.add("orderId2");
|
||||
Flux<SubscribeConfigurationResponse> subscription = client.subscribeConfiguration(DAPR_CONFIGURATON_STORE,keys);
|
||||
|
||||
// The metadata which will be sent to configuration store components.
|
||||
map<string,string> metadata = 3;
|
||||
// Read config changes for 20 seconds
|
||||
subscription.subscribe((response) -> {
|
||||
// First ever response contains the subscription id
|
||||
if (response.getItems() == null || response.getItems().isEmpty()) {
|
||||
subscriptionId = response.getSubscriptionId();
|
||||
System.out.println("App subscribed to config changes with subscription id: " + subscriptionId);
|
||||
} else {
|
||||
response.getItems().forEach((k, v) -> {
|
||||
System.out.println("Configuration update for " + k + ": {'value':'" + v.getValue() + "'}");
|
||||
});
|
||||
}
|
||||
});
|
||||
Thread.sleep(20000);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
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](https://grpc.io/docs/languages/) for usage.
|
||||
Navigate to the directory containing the above code, then run the following command to launch both a Dapr sidecar and the subscriber application:
|
||||
|
||||
Below are the examples in sdks:
|
||||
```bash
|
||||
dapr run --app-id orderprocessing -- -- mvn spring-boot:run
|
||||
|
||||
{{< tabs Python>}}
|
||||
{{% /codetab %}}
|
||||
|
||||
{{% codetab %}}
|
||||
|
||||
```python
|
||||
#dependencies
|
||||
from dapr.clients import DaprClient
|
||||
#code
|
||||
|
||||
def handler(id: str, resp: ConfigurationResponse):
|
||||
for key in resp.items:
|
||||
print(f"Subscribed item received key={key} value={resp.items[key].value} "
|
||||
f"version={resp.items[key].version} "
|
||||
f"metadata={resp.items[key].metadata}", flush=True)
|
||||
|
||||
def executeConfiguration():
|
||||
with DaprClient() as d:
|
||||
storeName = 'configurationstore'
|
||||
keys = ['orderId1', 'orderId2']
|
||||
id = d.subscribe_configuration(store_name=storeName, keys=keys,
|
||||
handler=handler, config_metadata={})
|
||||
print("Subscription ID is", id, flush=True)
|
||||
sleep(20)
|
||||
|
||||
executeConfiguration()
|
||||
```
|
||||
|
||||
Navigate to the directory containing the above code, then run the following command to launch both a Dapr sidecar and the subscriber application:
|
||||
|
||||
```bash
|
||||
dapr run --app-id orderprocessing -- python3 OrderProcessingService.py
|
||||
```
|
||||
|
||||
{{% /codetab %}}
|
||||
|
||||
{{% codetab %}}
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
dapr "github.com/dapr/go-sdk/client"
|
||||
)
|
||||
|
||||
func main() {
|
||||
ctx := context.Background()
|
||||
client, err := dapr.NewClient()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
subscribeID, err := client.SubscribeConfigurationItems(ctx, "configstore", []string{"orderId1", "orderId2"}, func(id string, items map[string]*dapr.ConfigurationItem) {
|
||||
for k, v := range items {
|
||||
fmt.Printf("get updated config key = %s, value = %s version = %s \n", k, v.Value, v.Version)
|
||||
}
|
||||
})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
time.Sleep(20*time.Second)
|
||||
}
|
||||
```
|
||||
|
||||
Navigate to the directory containing the above code, then run the following command to launch both a Dapr sidecar and the subscriber application:
|
||||
|
||||
```bash
|
||||
dapr run --app-id orderprocessing -- go run main.go
|
||||
```
|
||||
|
||||
{{% /codetab %}}
|
||||
|
||||
{{% codetab %}}
|
||||
|
||||
```js
|
||||
import { CommunicationProtocolEnum, DaprClient } from "@dapr/dapr";
|
||||
|
||||
// JS SDK does not support Configuration API over HTTP protocol yet
|
||||
const protocol = CommunicationProtocolEnum.GRPC;
|
||||
const host = process.env.DAPR_HOST ?? "localhost";
|
||||
const port = process.env.DAPR_GRPC_PORT ?? 3500;
|
||||
|
||||
const DAPR_CONFIGURATION_STORE = "configstore";
|
||||
const CONFIGURATION_ITEMS = ["orderId1", "orderId2"];
|
||||
|
||||
async function main() {
|
||||
const client = new DaprClient(host, port, protocol);
|
||||
// Subscribe to config updates
|
||||
try {
|
||||
const stream = await client.configuration.subscribeWithKeys(
|
||||
DAPR_CONFIGURATION_STORE,
|
||||
CONFIGURATION_ITEMS,
|
||||
(config) => {
|
||||
console.log("Configuration update", JSON.stringify(config.items));
|
||||
}
|
||||
);
|
||||
// Unsubscribe to config updates and exit app after 20 seconds
|
||||
setTimeout(() => {
|
||||
stream.stop();
|
||||
console.log("App unsubscribed to config changes");
|
||||
process.exit(0);
|
||||
}, 20000);
|
||||
} catch (error) {
|
||||
console.log("Error subscribing to config updates, err:" + error);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
main().catch((e) => console.error(e));
|
||||
```
|
||||
|
||||
Navigate to the directory containing the above code, then run the following command to launch both a Dapr sidecar and the subscriber application:
|
||||
|
||||
```bash
|
||||
dapr run --app-id orderprocessing --app-protocol grpc --dapr-grpc-port 3500 -- node index.js
|
||||
```
|
||||
|
||||
{{% /codetab %}}
|
||||
|
||||
{{< /tabs >}}
|
||||
|
||||
|
||||
### Unsubscribe from configuration item updates
|
||||
|
||||
After you've subscribed to watch configuration items, you will receive updates for all of the subscribed keys. To stop receiving updates, you need to explicitly call the unsubscribe API.
|
||||
|
||||
Following are the code examples showing how you can unsubscribe to configuration updates using unsubscribe API.
|
||||
|
||||
{{< tabs ".NET" Java Python Go Javascript "HTTP API (BASH)" "HTTP API (Powershell)">}}
|
||||
|
||||
{{% codetab %}}
|
||||
```csharp
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Dapr.Client;
|
||||
|
||||
const string DAPR_CONFIGURATION_STORE = "configstore";
|
||||
var client = new DaprClientBuilder().Build();
|
||||
|
||||
// Unsubscribe to config updates and exit the app
|
||||
async Task unsubscribe(string subscriptionId)
|
||||
{
|
||||
try
|
||||
{
|
||||
await client.UnsubscribeConfiguration(DAPR_CONFIGURATION_STORE, subscriptionId);
|
||||
Console.WriteLine("App unsubscribed from config changes");
|
||||
Environment.Exit(0);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine("Error unsubscribing from config updates: " + ex.Message);
|
||||
}
|
||||
}
|
||||
```
|
||||
{{% /codetab %}}
|
||||
|
||||
{{% codetab %}}
|
||||
```java
|
||||
import io.dapr.client.DaprClientBuilder;
|
||||
import io.dapr.client.DaprClient;
|
||||
import io.dapr.client.domain.ConfigurationItem;
|
||||
import io.dapr.client.domain.GetConfigurationRequest;
|
||||
import io.dapr.client.domain.SubscribeConfigurationRequest;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
//code
|
||||
private static final String CONFIG_STORE_NAME = "configstore";
|
||||
private static String subscriptionId = null;
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
try (DaprClient client = (new DaprClientBuilder()).build()) {
|
||||
// Unsubscribe from config changes
|
||||
UnsubscribeConfigurationResponse unsubscribe = client
|
||||
.unsubscribeConfiguration(subscriptionId, DAPR_CONFIGURATON_STORE).block();
|
||||
if (unsubscribe.getIsUnsubscribed()) {
|
||||
System.out.println("App unsubscribed to config changes");
|
||||
} else {
|
||||
System.out.println("Error unsubscribing to config updates, err:" + unsubscribe.getMessage());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
System.out.println("Error unsubscribing to config updates," + e.getMessage());
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
```
|
||||
{{% /codetab %}}
|
||||
|
||||
{{% codetab %}}
|
||||
```python
|
||||
#dependencies
|
||||
import asyncio
|
||||
import time
|
||||
import logging
|
||||
from dapr.clients import DaprClient
|
||||
#code
|
||||
async def executeConfiguration():
|
||||
with DaprClient() as d:
|
||||
CONFIG_STORE_NAME = 'configstore'
|
||||
key = 'orderId'
|
||||
# Subscribe to configuration by key.
|
||||
configuration = await d.subscribe_configuration(store_name=CONFIG_STORE_NAME, keys=[key], config_metadata={})
|
||||
if configuration != None:
|
||||
items = configuration.get_items()
|
||||
for item in items:
|
||||
print(f"Subscribe key={item.key} value={item.value} version={item.version}", flush=True)
|
||||
else:
|
||||
print("Nothing yet")
|
||||
asyncio.run(executeConfiguration())
|
||||
```
|
||||
subscriptionID = ""
|
||||
|
||||
```bash
|
||||
dapr run --app-id orderprocessing --resources-path components/ -- python3 OrderProcessingService.py
|
||||
with DaprClient() as d:
|
||||
isSuccess = d.unsubscribe_configuration(store_name='configstore', id=subscriptionID)
|
||||
print(f"Unsubscribed successfully? {isSuccess}", flush=True)
|
||||
```
|
||||
|
||||
{{% /codetab %}}
|
||||
|
||||
{{< /tabs >}}
|
||||
{{% codetab %}}
|
||||
```go
|
||||
package main
|
||||
|
||||
#### Stop watching configuration items
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
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:
|
||||
dapr "github.com/dapr/go-sdk/client"
|
||||
)
|
||||
|
||||
```proto
|
||||
// UnSubscribeConfigurationRequest is the message to stop watching the key-value configuration.
|
||||
message UnSubscribeConfigurationRequest {
|
||||
// The name of configuration store.
|
||||
string store_name = 1;
|
||||
// Optional. The keys of the configuration item to stop watching.
|
||||
// Store_name and keys should match previous SubscribeConfigurationRequest's keys and store_name.
|
||||
// Once invoked, the subscription that is watching update for the key-value event is stopped
|
||||
repeated string keys = 2;
|
||||
var DAPR_CONFIGURATION_STORE = "configstore"
|
||||
var subscriptionID = ""
|
||||
|
||||
func main() {
|
||||
client, err := dapr.NewClient()
|
||||
if err != nil {
|
||||
log.Panic(err)
|
||||
}
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
defer cancel()
|
||||
if err := client.UnsubscribeConfigurationItems(ctx, DAPR_CONFIGURATION_STORE , subscriptionID); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
```
|
||||
{{% /codetab %}}
|
||||
|
||||
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.
|
||||
{{% codetab %}}
|
||||
```js
|
||||
import { CommunicationProtocolEnum, DaprClient } from "@dapr/dapr";
|
||||
|
||||
// JS SDK does not support Configuration API over HTTP protocol yet
|
||||
const protocol = CommunicationProtocolEnum.GRPC;
|
||||
const host = process.env.DAPR_HOST ?? "localhost";
|
||||
const port = process.env.DAPR_GRPC_PORT ?? 3500;
|
||||
|
||||
const DAPR_CONFIGURATION_STORE = "configstore";
|
||||
const CONFIGURATION_ITEMS = ["orderId1", "orderId2"];
|
||||
|
||||
async function main() {
|
||||
const client = new DaprClient(host, port, protocol);
|
||||
|
||||
try {
|
||||
const stream = await client.configuration.subscribeWithKeys(
|
||||
DAPR_CONFIGURATION_STORE,
|
||||
CONFIGURATION_ITEMS,
|
||||
(config) => {
|
||||
console.log("Configuration update", JSON.stringify(config.items));
|
||||
}
|
||||
);
|
||||
setTimeout(() => {
|
||||
// Unsubscribe to config updates
|
||||
stream.stop();
|
||||
console.log("App unsubscribed to config changes");
|
||||
process.exit(0);
|
||||
}, 20000);
|
||||
} catch (error) {
|
||||
console.log("Error subscribing to config updates, err:" + error);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
main().catch((e) => console.error(e));
|
||||
```
|
||||
{{% /codetab %}}
|
||||
|
||||
{{% codetab %}}
|
||||
```bash
|
||||
curl 'http://localhost:<DAPR_HTTP_PORT>/v1.0/configuration/configstore/<subscription-id>/unsubscribe'
|
||||
```
|
||||
{{% /codetab %}}
|
||||
|
||||
{{% codetab %}}
|
||||
```powershell
|
||||
Invoke-RestMethod -Uri 'http://localhost:<DAPR_HTTP_PORT>/v1.0/configuration/configstore/<subscription-id>/unsubscribe'
|
||||
```
|
||||
{{% /codetab %}}
|
||||
|
||||
## Next steps
|
||||
|
||||
* Read [configuration API overview]({{< ref configuration-api-overview.md >}})
|
||||
* Read [configuration API overview]({{< ref configuration-api-overview.md >}})
|
||||
|
|
|
@ -13,7 +13,7 @@ This endpoint lets you get configuration from a store.
|
|||
### HTTP Request
|
||||
|
||||
```
|
||||
GET http://localhost:<daprPort>/v1.0-alpha1/configuration/<storename>
|
||||
GET http://localhost:<daprPort>/v1.0/configuration/<storename>
|
||||
```
|
||||
|
||||
#### URL Parameters
|
||||
|
@ -29,13 +29,13 @@ If no query parameters are provided, all configuration items are returned.
|
|||
To specify the keys of the configuration items to get, use one or more `key` query parameters. For example:
|
||||
|
||||
```
|
||||
GET http://localhost:<daprPort>/v1.0-alpha1/configuration/mystore?key=config1&key=config2
|
||||
GET http://localhost:<daprPort>/v1.0/configuration/mystore?key=config1&key=config2
|
||||
```
|
||||
|
||||
To retrieve all configuration items:
|
||||
|
||||
```
|
||||
GET http://localhost:<daprPort>/v1.0-alpha1/configuration/mystore
|
||||
GET http://localhost:<daprPort>/v1.0/configuration/mystore
|
||||
```
|
||||
|
||||
#### Request Body
|
||||
|
@ -59,7 +59,7 @@ JSON-encoded value of key/value pairs for each configuration item.
|
|||
### Example
|
||||
|
||||
```shell
|
||||
curl -X GET 'http://localhost:3500/v1.0-alpha1/configuration/mystore?key=myConfigKey'
|
||||
curl -X GET 'http://localhost:3500/v1.0/configuration/mystore?key=myConfigKey'
|
||||
```
|
||||
|
||||
> The above command returns the following JSON:
|
||||
|
@ -75,7 +75,7 @@ This endpoint lets you subscribe to configuration changes. Notifications happen
|
|||
### HTTP Request
|
||||
|
||||
```
|
||||
GET http://localhost:<daprPort>/v1.0-alpha1/configuration/<storename>/subscribe
|
||||
GET http://localhost:<daprPort>/v1.0/configuration/<storename>/subscribe
|
||||
```
|
||||
|
||||
#### URL Parameters
|
||||
|
@ -91,13 +91,13 @@ If no query parameters are provided, all configuration items are subscribed to.
|
|||
To specify the keys of the configuration items to subscribe to, use one or more `key` query parameters. For example:
|
||||
|
||||
```
|
||||
GET http://localhost:<daprPort>/v1.0-alpha1/configuration/mystore/subscribe?key=config1&key=config2
|
||||
GET http://localhost:<daprPort>/v1.0/configuration/mystore/subscribe?key=config1&key=config2
|
||||
```
|
||||
|
||||
To subscribe to all changes:
|
||||
|
||||
```
|
||||
GET http://localhost:<daprPort>/v1.0-alpha1/configuration/mystore/subscribe
|
||||
GET http://localhost:<daprPort>/v1.0/configuration/mystore/subscribe
|
||||
```
|
||||
|
||||
#### Request Body
|
||||
|
@ -121,7 +121,7 @@ JSON-encoded value
|
|||
### Example
|
||||
|
||||
```shell
|
||||
curl -X GET 'http://localhost:3500/v1.0-alpha1/configuration/mystore/subscribe?key=myConfigKey'
|
||||
curl -X GET 'http://localhost:3500/v1.0/configuration/mystore/subscribe?key=myConfigKey'
|
||||
```
|
||||
|
||||
> The above command returns the following JSON:
|
||||
|
@ -141,7 +141,7 @@ This endpoint lets you unsubscribe to configuration changes.
|
|||
### HTTP Request
|
||||
|
||||
```
|
||||
GET http://localhost:<daprPort>/v1.0-alpha1/configuration/<storename>/<subscription-id>/unsubscribe
|
||||
GET http://localhost:<daprPort>/v1.0/configuration/<storename>/<subscription-id>/unsubscribe
|
||||
```
|
||||
|
||||
#### URL Parameters
|
||||
|
@ -181,7 +181,7 @@ Code | Description
|
|||
### Example
|
||||
|
||||
```shell
|
||||
curl -X GET 'http://localhost:3500/v1.0-alpha1/configuration/mystore/bf3aa454-312d-403c-af95-6dec65058fa2/unsubscribe'
|
||||
curl -X GET 'http://localhost:3500/v1.0/configuration/mystore/bf3aa454-312d-403c-af95-6dec65058fa2/unsubscribe'
|
||||
```
|
||||
|
||||
## Optional application (user code) routes
|
||||
|
|
|
@ -100,7 +100,7 @@ The Azure App Configuration store component supports the following optional `lab
|
|||
The label can be populated using query parameters in the request URL:
|
||||
|
||||
```bash
|
||||
GET curl http://localhost:<daprPort>/v1.0-alpha1/configuration/<store-name>?key=<key name>&metadata.label=<label value>
|
||||
GET curl http://localhost:<daprPort>/v1.0/configuration/<store-name>?key=<key name>&metadata.label=<label value>
|
||||
```
|
||||
|
||||
## Related links
|
||||
|
|
|
@ -39,7 +39,7 @@ The above example uses secrets as plain strings. It is recommended to use a secr
|
|||
| Field | Required | Details | Example |
|
||||
|--------------------|:--------:|---------|---------|
|
||||
| connectionString | Y | The connection string for PostgreSQL. Default pool_max_conns = 5 | `"host=localhost user=postgres password=example port=5432 connect_timeout=10 database=dapr_test pool_max_conns=10"`
|
||||
| table | Y | table name for configuration information. | `configTable`
|
||||
| table | Y | Table name for configuration information, must be lowercased. | `configtable`
|
||||
|
||||
## Set up PostgreSQL as Configuration Store
|
||||
|
||||
|
@ -96,7 +96,7 @@ notification = json_build_object(
|
|||
6. Since this is a generic created trigger, map this trigger to `configuration table`
|
||||
```console
|
||||
CREATE TRIGGER config
|
||||
AFTER INSERT OR UPDATE OR DELETE ON configTable
|
||||
AFTER INSERT OR UPDATE OR DELETE ON configtable
|
||||
FOR EACH ROW EXECUTE PROCEDURE notify_event();
|
||||
```
|
||||
7. In the subscribe request add an additional metadata field with key as `pgNotifyChannel` and value should be set to same `channel name` mentioned in `pg_notify`. From the above example, it should be set to `config`
|
||||
|
|
|
@ -20,19 +20,11 @@ spec:
|
|||
version: v1
|
||||
metadata:
|
||||
- name: redisHost
|
||||
value: <HOST>
|
||||
value: <address>:6379
|
||||
- name: redisPassword
|
||||
value: <PASSWORD>
|
||||
value: **************
|
||||
- name: enableTLS
|
||||
value: <bool> # Optional. Allowed: true, false.
|
||||
- name: failover
|
||||
value: <bool> # Optional. Allowed: true, false.
|
||||
- name: sentinelMasterName
|
||||
value: <string> # Optional
|
||||
- name: maxRetries
|
||||
value: # Optional
|
||||
- name: maxRetryBackoff
|
||||
value: # Optional
|
||||
value: <bool>
|
||||
|
||||
```
|
||||
|
||||
|
@ -45,14 +37,26 @@ The above example uses secrets as plain strings. It is recommended to use a secr
|
|||
|
||||
| Field | Required | Details | Example |
|
||||
|--------------------|:--------:|---------|---------|
|
||||
| redisHost | Y | Connection-string for the redis host | `localhost:6379`, `redis-master.default.svc.cluster.local:6379`
|
||||
| redisPassword | Y | Password for Redis host. No Default. Can be `secretKeyRef` to use a secret reference | `""`, `"KeFg23!"`
|
||||
| enableTLS | N | If the Redis instance supports TLS with public certificates, can be configured to be enabled or disabled. Defaults to `"false"` | `"true"`, `"false"`
|
||||
| maxRetries | N | Maximum number of retries before giving up. Defaults to `3` | `5`, `10`
|
||||
| maxRetryBackoff | N | Maximum backoff between each retry. Defaults to `2` seconds; `"-1"` disables backoff. | `3000000000`
|
||||
| failover | N | Property to enabled failover configuration. Needs sentinalMasterName to be set. The redisHost should be the sentinel host address. See [Redis Sentinel Documentation](https://redis.io/docs/manual/sentinel/). Defaults to `"false"` | `"true"`, `"false"`
|
||||
| sentinelMasterName | N | The sentinel master name. See [Redis Sentinel Documentation](https://redis.io/docs/manual/sentinel/) | `""`, `"127.0.0.1:6379"`
|
||||
|
||||
| redisHost | Y | Output | The Redis host address | `"localhost:6379"` |
|
||||
| redisPassword | Y | Output | The Redis password | `"password"` |
|
||||
| redisUsername | N | Output | Username for Redis host. Defaults to empty. Make sure your Redis server version is 6 or above, and have created acl rule correctly. | `"username"` |
|
||||
| enableTLS | N | Output | If the Redis instance supports TLS with public certificates it can be configured to enable or disable TLS. Defaults to `"false"` | `"true"`, `"false"` |
|
||||
| failover | N | Output | Property to enabled failover configuration. Needs sentinelMasterName to be set. Defaults to `"false"` | `"true"`, `"false"`
|
||||
| sentinelMasterName | N | Output | The Sentinel master name. See [Redis Sentinel Documentation](https://redis.io/docs/reference/sentinel-clients/) | `""`, `"127.0.0.1:6379"`
|
||||
| redisType | N | Output | The type of Redis. There are two valid values, one is `"node"` for single node mode, the other is `"cluster"` for Redis cluster mode. Defaults to `"node"`. | `"cluster"`
|
||||
| redisDB | N | Output | Database selected after connecting to Redis. If `"redisType"` is `"cluster"`, this option is ignored. Defaults to `"0"`. | `"0"`
|
||||
| redisMaxRetries | N | Output | Maximum number of times to retry commands before giving up. Default is to not retry failed commands. | `"5"`
|
||||
| redisMinRetryInterval | N | Output | Minimum backoff for Redis commands between each retry. Default is `"8ms"`; `"-1"` disables backoff. | `"8ms"`
|
||||
| redisMaxRetryInterval | N | Output | Maximum backoff for Redis commands between each retry. Default is `"512ms"`;`"-1"` disables backoff. | `"5s"`
|
||||
| dialTimeout | N | Output | Dial timeout for establishing new connections. Defaults to `"5s"`. | `"5s"`
|
||||
| readTimeout | N | Output | Timeout for socket reads. If reached, Redis commands fail with a timeout instead of blocking. Defaults to `"3s"`, `"-1"` for no timeout. | `"3s"`
|
||||
| writeTimeout | N | Output | Timeout for socket writes. If reached, Redis commands fail with a timeout instead of blocking. Defaults is readTimeout. | `"3s"`
|
||||
| poolSize | N | Output | Maximum number of socket connections. Default is 10 connections per every CPU as reported by runtime.NumCPU. | `"20"`
|
||||
| poolTimeout | N | Output | Amount of time client waits for a connection if all connections are busy before returning an error. Default is readTimeout + 1 second. | `"5s"`
|
||||
| maxConnAge | N | Output | Connection age at which the client retires (closes) the connection. Default is to not close aged connections. | `"30m"`
|
||||
| minIdleConns | N | Output | Minimum number of idle connections to keep open in order to avoid the performance degradation associated with creating new connections. Defaults to `"0"`. | `"2"`
|
||||
| idleCheckFrequency | N | Output | Frequency of idle checks made by idle connections reaper. Default is `"1m"`. `"-1"` disables idle connections reaper. | `"-1"`
|
||||
| idleTimeout | N | Output | Amount of time after which the client closes idle connections. Should be less than server's timeout. Default is `"5m"`. `"-1"` disables idle timeout check. | `"10m"`
|
||||
|
||||
## Setup Redis
|
||||
|
||||
|
|
Loading…
Reference in New Issue