Merge branch 'dapr:master' into fix-556

This commit is contained in:
Francesco Belacca 2022-12-12 22:06:21 +01:00 committed by GitHub
commit 2358f3e0a1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
53 changed files with 11119 additions and 2 deletions

View File

@ -0,0 +1,103 @@
#
# Copyright 2022 The Dapr Authors
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
name: Validate Configuration API
on:
workflow_dispatch:
push:
branches:
- master
- feature/new_quickstarts
- release-*
tags:
- v*
pull_request:
branches:
- master
- feature/new_quickstarts
- release-*
jobs:
validate:
name: Validate quickstart for `${{ matrix.quickstart_language }}` with `${{ matrix.quickstart_variant }}` on ${{ matrix.os }}
runs-on: ${{ matrix.os }}
env:
DAPR_INSTALL_URL: https://raw.githubusercontent.com/dapr/cli/master/install
GOVER: 1.18
KUBERNETES_VERSION: v1.25.3
KIND_VERSION: v0.17.0
KIND_IMAGE_SHA: sha256:f52781bc0d7a19fb6c405c2af83abfeb311f130707a0e219175677e366cc45d1
strategy:
matrix:
os: [ubuntu-latest, macos-10.15]
quickstart_language: [go, csharp, javascript, python, java]
quickstart_variant: [http, sdk]
steps:
- name: Install docker - MacOS
if: matrix.os == 'macos-10.15'
uses: docker-practice/actions-setup-docker@v1
with:
docker_buildx: false
docker_version: 20.10.21
- name: Set up Go ${{ env.GOVER }}
uses: actions/setup-go@v2
with:
go-version: ${{ env.GOVER }}
- name: Set up OpenJDK 11
uses: actions/setup-java@v3
with:
distribution: 'adopt'
java-version: 11
- name: Install .NET Core
uses: actions/setup-dotnet@v1.9.0
with:
dotnet-version: |
6.0.x
- name: Determine latest Dapr Runtime version including Pre-releases
run: |
helm repo add dapr https://dapr.github.io/helm-charts/ && helm repo update && export RUNTIME_VERSION=$(helm search repo dapr/dapr --devel --versions | awk '/dapr\/dapr/ {print $3; exit}' )
echo "DAPR_RUNTIME_VERSION=$RUNTIME_VERSION" >> $GITHUB_ENV
echo "Found $RUNTIME_VERSION"
shell: bash
- name: Determine latest Dapr Cli version including Pre-releases
run: |
export CLI_VERSION=$(curl "https://api.github.com/repos/dapr/cli/releases?per_page=1&page=1" --header 'authorization: Bearer ${{ secrets.GITHUB_TOKEN }}' | jq '.[0].tag_name'| tr -d '",v')
echo "DAPR_CLI_VERSION=$CLI_VERSION" >> $GITHUB_ENV
echo "Found $CLI_VERSION"
shell: bash
- name: Set up Dapr CLI - Mac/Linux
if: matrix.os != 'windows-latest'
run: wget -q ${{ env.DAPR_INSTALL_URL }}/install.sh -O - | /bin/bash -s ${{ env.DAPR_CLI_VERSION }}
- name: Set up Dapr CLI - Windows
if: matrix.os == 'windows-latest'
run: powershell -Command "\$$script=iwr -useb ${{ env.DAPR_INSTALL_URL }}/install.ps1; \$$block=[ScriptBlock]::Create(\$$script); invoke-command -ScriptBlock \$$block -ArgumentList ${{ env.DAPR_CLI_VERSION }}"
- name: Install Dapr
run: |
export GITHUB_TOKEN=${{ secrets.GITHUB_TOKEN }}
dapr init --runtime-version=${{ env.DAPR_RUNTIME_VERSION }}
dapr --version
- name: Check out code
uses: actions/checkout@v2
- name: Install utilities dependencies
run: |
echo "PATH=$PATH:$HOME/.local/bin" >> $GITHUB_ENV
pip3 install setuptools wheel
pip3 install mechanical-markdown
- name: Validate ${{ matrix.quickstart_language }} ${{ matrix.quickstart_variant }} Configuration API
run: |
pushd configuration/${{ matrix.quickstart_language }}/${{ matrix.quickstart_variant }}
make validate
popd
- name: Linkcheck README.md
run: |
make validate

View File

@ -17,8 +17,7 @@ Pick a building block API (for example, pub-sub, state management) and rapidly t
| [Bindings](./bindings/) | Work with external systems using input bindings to respond to events and output bindings to call operations|
| [Secrets Management](./secrets_management/) | Securely fetch secrets |
| Actors | Coming soon... |
| Observability | Coming soon... |
| Configuration | Coming soon... |
| [Configuration](./configuration) | Get configuration items as key/value pairs or subscribe to changes whenever a configuration item changes |
### Tutorials
Go deeper into a topic or scenario, oftentimes using building block APIs together to solve problems (for example, build a distributed calculator, build and deploy an app to Kubernetes).

View File

@ -0,0 +1,12 @@
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
name: configstore
spec:
type: configuration.redis
version: v1
metadata:
- name: redisHost
value: localhost:6379
- name: redisPassword
value: ""

View File

@ -0,0 +1,71 @@
# Dapr Configuration API
In this quickstart, you'll create a microservice which makes use of Dapr's Configuration API. Configuration items are key/value pairs containing configuration data such as app ids, partition keys, database names etc. The service gets configuration items from the configuration store and subscribes for configuration updates.
Visit [this](https://docs.dapr.io/developing-applications/building-blocks/configuration/) link for more information about Dapr and Configuration API.
> **Note:** This example leverages HTTP `requests` only. If you are looking for the example using the Dapr Client SDK (recommended) [click here](../sdk/).
This quickstart includes one service:
- Dotnet service `order-processor`
## Add configuration items to the config store
### Prerequisite
- Locally running redis container - a redis container named `dapr_redis` is automatically created when you run `dapr init`
- Open a new terminal and set values for config items `orderId1` and `orderId2` by using the command below
<!-- STEP
name: Add configuration items
expected_stdout_lines:
- 'OK'
-->
```bash
docker exec dapr_redis redis-cli MSET orderId1 "101" orderId2 "102"
```
<!-- END_STEP -->
## Run order-processor
1. Open a new terminal and navigate to `order-processor` directory.
2. Run the service app with Dapr.
<!-- STEP
name: Run order-processor service
expected_stdout_lines:
- '== APP == Configuration for orderId1: {"orderId1":{"value":"101"}}'
- '== APP == Configuration for orderId2: {"orderId2":{"value":"102"}}'
- '== APP == App subscribed to config changes with subscription id:'
- '== APP == App unsubscribed from config updates'
- "Exited App successfully"
expected_stderr_lines:
output_match_mode: substring
match_order: none
-->
```bash
cd ./order-processor
dapr run --app-id order-processor-http --components-path ../../../components/ --app-port 7001 -- dotnet run --project .
```
<!-- END_STEP -->
## (Optional) Update value of config items
1. Keep the `order-processor` app running and open a separate terminal
2. Change the values of `orderId1` and `orderId2` using the command below
3. `order-processor` app gets the updated values of config items
<!-- STEP
name: Update config items
-->
```bash
docker exec dapr_redis redis-cli MSET orderId1 "103" orderId2 "104"
```
<!--END_STEP -->

View File

@ -0,0 +1,2 @@
include ../../../docker.mk
include ../../../validate.mk

View File

@ -0,0 +1,94 @@
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
var baseURL = (Environment.GetEnvironmentVariable("BASE_URL") ?? "http://localhost") + ":"
+ (Environment.GetEnvironmentVariable("DAPR_HTTP_PORT") ?? "3500");
const string DAPR_CONFIGURATION_STORE = "configstore";
var CONFIGURATION_ITEMS = new List<string> { "orderId1", "orderId2" };
var httpClient = new HttpClient();
httpClient.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
foreach (var item in CONFIGURATION_ITEMS)
{
// Get config items from the config store
try
{
var response = await httpClient.GetStringAsync($"{baseURL}/v1.0-alpha1/configuration/{DAPR_CONFIGURATION_STORE}?key={item.ToString()}");
Console.WriteLine("Configuration for " + item + ": " + response);
}
catch (Exception ex)
{
Console.WriteLine("Could not get config item, err:" + ex.Message);
Environment.Exit(1);
}
}
async Task<string> subscribeToConfigUpdates()
{
// Add delay to allow app channel to be ready
Thread.Sleep(3000);
try
{
var subscription = await httpClient.GetStringAsync($"{baseURL}/v1.0-alpha1/configuration/{DAPR_CONFIGURATION_STORE}/subscribe");
if (subscription.Contains("errorCode"))
{
Console.WriteLine("Error subscribing to config updates, err:" + subscription);
Environment.Exit(1);
return string.Empty;
}
dynamic data = JObject.Parse(subscription);
Console.WriteLine("App subscribed to config changes with subscription id: " + data.id);
return data.id;
}
catch (Exception ex)
{
Console.WriteLine("Error subscribing to config updates, err:" + ex.Message);
Environment.Exit(1);
return string.Empty;
}
}
async Task readConfigurationChanges()
{
// Create POST endpoint to receive config updates
app.MapPost("/configuration/configstore/{item}", async (HttpRequest request) =>
{
using var sr = new StreamReader(request.Body);
var config = await sr.ReadToEndAsync();
dynamic update = JObject.Parse(config);
Console.WriteLine("Configuration update " + update.items.ToString(Formatting.None));
});
await app.StartAsync();
}
await readConfigurationChanges();
string subscriptionId = await subscribeToConfigUpdates();
// Unsubscribe to config updates and exit app after 20 seconds
await Task.Delay(20000);
try
{
string unsubscribe = await httpClient.GetStringAsync($"{baseURL}/v1.0-alpha1/configuration/{DAPR_CONFIGURATION_STORE}/{subscriptionId}/unsubscribe");
if (unsubscribe.Contains("true"))
{
Console.WriteLine("App unsubscribed from config updates");
Environment.Exit(0);
}
else
{
Console.WriteLine("Error unsubscribing from config updates, err:" + unsubscribe);
Environment.Exit(1);
}
}
catch (Exception ex)
{
Console.WriteLine("Error unsubscribing from config updates, err:" + ex.Message);
Environment.Exit(1);
}

View File

@ -0,0 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.2.3" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,15 @@
{
"$schema": "http://json.schemastore.org/launchsettings.json",
"profiles": {
"CheckoutService": {
"commandName": "Project",
"dotnetRunMessages": "true",
"launchBrowser": true,
"launchUrl": "swagger",
"applicationUrl": "http://localhost:7001",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}

View File

@ -0,0 +1,9 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
}
}

View File

@ -0,0 +1,10 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*"
}

View File

@ -0,0 +1,69 @@
# Dapr Configuration API
In this quickstart, you'll create a microservice which makes use of Dapr's Configuration API. Configuration items are key/value pairs containing configuration data such as app ids, partition keys, database names etc. The service gets configuration items from the configuration store and subscribes for configuration updates.
Visit [this](https://docs.dapr.io/developing-applications/building-blocks/configuration/) link for more information about Dapr and Configuration API.
This quickstart includes one service:
- Dotnet service `order-processor`
## Add configuration items to the config store
### Prerequisite
- Locally running redis container - a redis container named `dapr_redis` is automatically created when you run `dapr init`
- Open a new terminal and set values for config items `orderId1` and `orderId2` by using the command below
<!-- STEP
name: Add configuration items
expected_stdout_lines:
- 'OK'
-->
```bash
docker exec dapr_redis redis-cli MSET orderId1 "101" orderId2 "102"
```
<!-- END_STEP -->
## Run order-processor
1. Open a new terminal and navigate to `order-processor` directory.
2. Run the service app with Dapr.
<!-- STEP
name: Run order-processor service
expected_stdout_lines:
- '== APP == Configuration for orderId1: {"Value":"101","Version":"","Metadata":{}}'
- '== APP == Configuration for orderId2: {"Value":"102","Version":"","Metadata":{}}'
- '== APP == App subscribed to config changes with subscription id:'
- '== APP == App unsubscribed from config changes'
- "Exited App successfully"
expected_stderr_lines:
output_match_mode: substring
match_order: none
-->
```bash
cd ./order-processor
dapr run --app-id order-processor-http --components-path ../../../components/ --app-port 7001 -- dotnet run --project .
```
<!-- END_STEP -->
## (Optional) Update value of config items
1. Keep the `order-processor` app running and open a separate terminal
2. Change the values of `orderId1` and `orderId2` using the command below
3. `order-processor` app gets the updated values of config items
<!-- STEP
name: Update config items
-->
```bash
docker exec dapr_redis redis-cli MSET orderId1 "103" orderId2 "104"
```
<!--END_STEP -->

View File

@ -0,0 +1,2 @@
include ../../../docker.mk
include ../../../validate.mk

View File

@ -0,0 +1,57 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Dapr.Client;
const string DAPR_CONFIGURATION_STORE = "configstore";
var CONFIGURATION_ITEMS = new List<string> { "orderId1", "orderId2" };
string subscriptionId = string.Empty;
var client = new DaprClientBuilder().Build();
// Get config from configuration store
GetConfigurationResponse config = await client.GetConfiguration(DAPR_CONFIGURATION_STORE, CONFIGURATION_ITEMS);
foreach (var item in config.Items)
{
var cfg = System.Text.Json.JsonSerializer.Serialize(item.Value);
Console.WriteLine("Configuration for " + item.Key + ": " + cfg);
}
// Exit the app after 20 seconds
var shutdownTimer = new System.Timers.Timer();
shutdownTimer.Interval = 20000;
shutdownTimer.Elapsed += (o, e) => unsubscribe(subscriptionId);
shutdownTimer.Start();
// Subscribe for configuration changes
SubscribeConfigurationResponse subscribe = await client.SubscribeConfiguration(DAPR_CONFIGURATION_STORE, CONFIGURATION_ITEMS);
// Print configuration changes
await foreach (var configItem in subscribe.Source)
{
// First invocation when app subscribes to config changes only returns subscription id
if (configItem.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(configItem);
Console.WriteLine("Configuration update " + cfg);
}
// Unsubscribe to config updates and exit the app
void unsubscribe(string subscriptionId)
{
try
{
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);
}
}

View File

@ -0,0 +1,12 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Dapr.AspNetCore" Version="1.9.0" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,73 @@
# Dapr Configuration API
In this quickstart, you'll create a microservice which makes use of Dapr's Configuration API. Configuration items are key/value pairs containing configuration data such as app ids, partition keys, database names etc. The service gets configuration items from the configuration store and subscribes for configuration updates.
Visit [this](https://docs.dapr.io/developing-applications/building-blocks/configuration/) link for more information about Dapr and Configuration API.
> **Note:** This example leverages HTTP `requests` only. If you are looking for the example using the Dapr Client SDK (recommended) [click here](../sdk/).
This quickstart includes one service:
- Go service `order-processor`
## Add configuration items to the config store
### Prerequisite
- Locally running redis container - a redis container named `dapr_redis` is automatically created when you run `dapr init`
- Open a new terminal and set values for config items `orderId1` and `orderId2` by using the command below
<!-- STEP
name: Add configuration items
expected_stdout_lines:
- 'OK'
-->
```bash
docker exec dapr_redis redis-cli MSET orderId1 "101" orderId2 "102"
```
<!-- END_STEP -->
## Run order-processor
1. Navigate to `order-processor` directory.
2. Run the service app with Dapr.
<!-- STEP
name: Run order-processor service
expected_stdout_lines:
- '== APP == Configuration for orderId1: {"orderId1":{"value":"101"}}'
- '== APP == Configuration for orderId2: {"orderId2":{"value":"102"}}'
- '== APP == App subscribed to config changes with subscription id:'
- '== APP == Shutting down HTTP server'
- '== APP == App unsubscribed from config changes'
- "Exited App successfully"
expected_stderr_lines:
output_match_mode: substring
match_order: none
-->
```bash
cd ./order-processor
dapr run --app-id order-processor --app-port 6001 --components-path ../../../components -- go run .
```
<!-- END_STEP -->
## (Optional) Update value of config items
1. Keep the `order-processor` app running and open a separate terminal
2. Change the values of `orderId1` and `orderId2` using the command below
3. `order-processor` app gets the updated values of config items
<!-- STEP
name: Update config items
-->
```bash
docker exec dapr_redis redis-cli MSET orderId1 "103" orderId2 "104"
```
<!--END_STEP -->

View File

@ -0,0 +1,2 @@
include ../../../docker.mk
include ../../../validate.mk

View File

@ -0,0 +1,138 @@
package main
import (
"context"
"encoding/json"
"fmt"
"io/ioutil"
"log"
"net/http"
"os"
"strings"
"sync"
"time"
"github.com/gorilla/mux"
)
var DAPR_HOST, DAPR_HTTP_PORT string
var okHost, okPort bool
var appPort = "6001"
var DAPR_CONFIGURATION_STORE = "configstore"
var CONFIGURATION_ITEMS = []string{"orderId1", "orderId2"}
func main() {
if DAPR_HOST, okHost = os.LookupEnv("DAPR_HOST"); !okHost {
DAPR_HOST = "http://localhost"
}
if DAPR_HTTP_PORT, okPort = os.LookupEnv("DAPR_HTTP_PORT"); !okPort {
DAPR_HTTP_PORT = "3500"
}
if value, ok := os.LookupEnv("APP_PORT"); ok {
appPort = value
}
// Get config items from the config store
for _, item := range CONFIGURATION_ITEMS {
getResponse, err := http.Get(DAPR_HOST + ":" + DAPR_HTTP_PORT + "/v1.0-alpha1/configuration/" + DAPR_CONFIGURATION_STORE + "?key=" + item)
if err != nil {
fmt.Print("Could not get config item, err:" + err.Error())
os.Exit(1)
}
result, _ := ioutil.ReadAll(getResponse.Body)
fmt.Println("Configuration for "+item+":", string(result))
}
var subscriptionId string
wg := new(sync.WaitGroup)
wg.Add(2)
// Start HTTP Server to receive config updates for 20 seconds and then shutdown and unsubscribe from config updates
go func() {
startServerToListen(&subscriptionId)
wg.Done()
}()
// Subscribe for config updates
go func() {
subscribeToConfigUpdates(&subscriptionId)
wg.Done()
}()
wg.Wait()
}
func subscribeToConfigUpdates(subscriptionId *string) {
// Add delay to allow app channel to be ready
time.Sleep(3 * time.Second)
subscription, err := http.Get(DAPR_HOST + ":" + DAPR_HTTP_PORT + "/v1.0-alpha1/configuration/" + DAPR_CONFIGURATION_STORE + "/subscribe")
if err != nil {
fmt.Println("Error subscribing to config updates, err:" + err.Error())
os.Exit(1)
}
sub, err := ioutil.ReadAll(subscription.Body)
if err != nil {
fmt.Print("Unable to read subscription id, err: " + err.Error())
os.Exit(1)
}
if !strings.Contains(string(sub), "errorCode") {
var subid map[string]interface{}
json.Unmarshal(sub, &subid)
fmt.Println("App subscribed to config changes with subscription id:", subid["id"])
*subscriptionId = subid["id"].(string)
} else {
fmt.Println("Error subscribing to config updates: ", string(sub))
os.Exit(1)
}
}
func startServerToListen(subscriptionId *string) {
r := mux.NewRouter()
httpServer := http.Server{
Addr: ":" + appPort,
Handler: r,
}
r.HandleFunc("/configuration/configstore/{configItem}", configUpdateHandler).Methods("POST")
// Unsubscribe to config updates and shutdown http server after 20 seconds
time.AfterFunc(20*time.Second, func() {
unsubscribeFromConfigUpdates(*subscriptionId)
fmt.Println("Shutting down HTTP server")
err := httpServer.Shutdown(context.Background())
if err != nil {
fmt.Println("Error shutting down HTTP server, err:" + err.Error())
}
})
// Start HTTP server
if err := httpServer.ListenAndServe(); err != nil {
log.Println("HTTP server error:", err)
}
}
func unsubscribeFromConfigUpdates(subscriptionId string) {
unsubscribe, err := http.Get(DAPR_HOST + ":" + DAPR_HTTP_PORT + "/v1.0-alpha1/configuration/" + DAPR_CONFIGURATION_STORE + "/" + subscriptionId + "/unsubscribe")
if err != nil {
fmt.Println("Error unsubscribing from config updates, err:" + err.Error())
}
unsub, err := ioutil.ReadAll(unsubscribe.Body)
if err != nil {
fmt.Print("Unable to read unsubscribe response, err: " + err.Error())
}
if strings.Contains(string(unsub), "true") {
fmt.Println("App unsubscribed from config changes")
return
} else {
fmt.Println("Error unsubscribing from config updates: ", string(unsub))
}
}
func configUpdateHandler(w http.ResponseWriter, r *http.Request) {
body, err := ioutil.ReadAll(r.Body)
if err != nil {
log.Panic(err)
}
var notification map[string]interface{}
json.Unmarshal(body, &notification)
update, _ := json.Marshal(notification["items"])
fmt.Println("Configuration update", string(update))
}

View File

@ -0,0 +1,5 @@
module dapr_example
go 1.18
require github.com/gorilla/mux v1.8.0

View File

@ -0,0 +1,2 @@
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=

View File

@ -0,0 +1,69 @@
# Dapr Configuration API
In this quickstart, you'll create a microservice which makes use of Dapr's Configuration API. Configuration items are key/value pairs containing configuration data such as app ids, partition keys, database names etc. The service gets configuration items from the configuration store and subscribes for configuration updates.
Visit [this](https://docs.dapr.io/developing-applications/building-blocks/configuration/) link for more information about Dapr and Configuration API.
This quickstart includes one service:
- Go service `order-processor`
## Add configuration items to the config store
### Prerequisite
- Locally running redis container - a redis container named `dapr_redis` is automatically created when you run `dapr init`
- Open a new terminal and set values for config items `orderId1` and `orderId2` by using the command below
<!-- STEP
name: Add configuration items
expected_stdout_lines:
- 'OK'
-->
```bash
docker exec dapr_redis redis-cli MSET orderId1 "101" orderId2 "102"
```
<!-- END_STEP -->
## Run order-processor
1. Open a new terminal and navigate to `order-processor` directory.
2. Run the service app with Dapr.
<!-- STEP
name: Run order-processor service
expected_stdout_lines:
- '== APP == Configuration for orderId1: {"Value":"101","Version":"","Metadata":null}'
- '== APP == Configuration for orderId2: {"Value":"102","Version":"","Metadata":null}'
- '== APP == App subscribed to config changes with subscription id:'
- '== APP == App unsubscribed to config changes'
- "Exited App successfully"
expected_stderr_lines:
output_match_mode: substring
match_order: none
-->
```bash
cd ./order-processor
dapr run --app-id order-processor --app-port 6001 --components-path ../../../components -- go run .
```
<!-- END_STEP -->
## (Optional) Update value of config items
1. Keep the `order-processor` app running and open a separate terminal
2. Change the values of `orderId1` and `orderId2` using the command below
3. `order-processor` app gets the updated values of config items
<!-- STEP
name: Update config items
-->
```bash
docker exec dapr_redis redis-cli MSET orderId1 "103" orderId2 "104"
```
<!--END_STEP -->

View File

@ -0,0 +1,2 @@
include ../../../docker.mk
include ../../../validate.mk

View File

@ -0,0 +1,67 @@
package main
import (
"context"
"encoding/json"
"fmt"
"log"
"os"
"time"
dapr "github.com/dapr/go-sdk/client"
)
var DAPR_CONFIGURATION_STORE = "configstore"
var CONFIGURATION_ITEMS = []string{"orderId1", "orderId2"}
func main() {
client, err := dapr.NewClient()
if err != nil {
log.Panic(err)
}
ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second)
defer cancel()
// Get config items from config store
for _, item := range CONFIGURATION_ITEMS {
config, err := client.GetConfigurationItem(ctx, DAPR_CONFIGURATION_STORE, item)
if err != nil {
fmt.Printf("Could not get config item, err:" + err.Error())
os.Exit(1)
}
c, _ := json.Marshal(config)
fmt.Println("Configuration for " + item + ": " + string(c))
}
var subscriptionId string
// Subscribe for config changes
err = client.SubscribeConfigurationItems(ctx, DAPR_CONFIGURATION_STORE, CONFIGURATION_ITEMS, func(id string, config map[string]*dapr.ConfigurationItem) {
// First invocation when app subscribes to config changes only returns subscription id
if len(config) == 0 {
fmt.Println("App subscribed to config changes with subscription id: " + id)
subscriptionId = id
return
}
// Print config changes
c, _ := json.Marshal(config)
fmt.Println("Configuration update " + string(c))
})
if err != nil {
fmt.Println("Error subscribing to config updates, err:" + err.Error())
os.Exit(1)
}
// Unsubscribe to config updates and exit app after 20 seconds
select {
case <-ctx.Done():
err = client.UnsubscribeConfigurationItems(context.Background(), DAPR_CONFIGURATION_STORE, subscriptionId)
if err != nil {
fmt.Println("Error unsubscribing to config updates, err:" + err.Error())
} else {
fmt.Println("App unsubscribed to config changes")
}
os.Exit(0)
default:
}
}

View File

@ -0,0 +1,18 @@
module dapr_example
go 1.18
require github.com/dapr/go-sdk v1.6.0
require (
github.com/golang/protobuf v1.5.2 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/stretchr/testify v1.8.0 // indirect
golang.org/x/net v0.0.0-20220927171203-f486391704dc // indirect
golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec // indirect
golang.org/x/text v0.3.7 // indirect
google.golang.org/genproto v0.0.0-20220622171453-ea41d75dfa0f // indirect
google.golang.org/grpc v1.48.0 // indirect
google.golang.org/protobuf v1.28.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

View File

@ -0,0 +1,156 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI=
github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/dapr/go-sdk v1.6.0 h1:jg5A2khSCHF8bGZsig5RWN/gD0jjitszc2V6Uq2pPdY=
github.com/dapr/go-sdk v1.6.0/go.mod h1:KLQBltoD9K0w5hKTihdcyg9Epob9gypwL5dYcQzPro4=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20220927171203-f486391704dc h1:FxpXZdoBqT8RjqTy6i1E8nXHhW21wK7ptQ/EPIGxzPQ=
golang.org/x/net v0.0.0-20220927171203-f486391704dc/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec h1:BkDtF2Ih9xZ7le9ndzTA7KJow28VbQW3odyk/8drmuI=
golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/genproto v0.0.0-20220622171453-ea41d75dfa0f h1:kYlCnpX4eB0QEnXm12j4DAX4yrjjhJmsyuWtSSZ+Buo=
google.golang.org/genproto v0.0.0-20220622171453-ea41d75dfa0f/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
google.golang.org/grpc v1.47.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
google.golang.org/grpc v1.48.0 h1:rQOsyJ/8+ufEDJd/Gdsz7HG220Mh9HAhFHRGnIjda0w=
google.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw=
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=

View File

@ -0,0 +1,92 @@
# Dapr Configuration API
In this quickstart, you'll create a microservice which makes use of Dapr's Configuration API. Configuration items are key/value pairs containing configuration data such as app ids, partition keys, database names etc. The service gets configuration items from the configuration store and subscribes for configuration updates.
Visit [this](https://docs.dapr.io/developing-applications/building-blocks/configuration/) link for more information about Dapr and Configuration API.
> **Note:** This example leverages HTTP `requests` only. If you are looking for the example using the Dapr Client SDK (recommended) [click here](../sdk/).
This quickstart includes one service:
- Java service `order-processor`
## Prerequisites
- [Maven 3.x](https://maven.apache.org/install.html)
- Java JDK 11 (or greater):
- [Microsoft JDK 11](https://docs.microsoft.com/en-us/java/openjdk/download#openjdk-11)
- [Oracle JDK 11](https://www.oracle.com/technetwork/java/javase/downloads/index.html#JDK11)
- [OpenJDK 11](https://jdk.java.net/11/)
- Locally running redis container - a redis container named `dapr_redis` is automatically created when you run `dapr init`
## Add configuration items to the config store
- Open a new terminal and set values for config items `orderId1` and `orderId2` by using the command below
<!-- STEP
name: Add configuration items
expected_stdout_lines:
- 'OK'
-->
```bash
docker exec dapr_redis redis-cli MSET orderId1 "101" orderId2 "102"
```
<!-- END_STEP -->
## Build the Java file
<!-- STEP
name: Build Java file
-->
```bash
cd ./order-processor
mvn clean install
```
<!-- END_STEP -->
## Run order-processor
1. Navigate to `order-processor` directory.
2. Run the service app with Dapr.
<!-- STEP
name: Run order-processor service
expected_stdout_lines:
- '== APP == Configuration for orderId1:{"orderId1":{"value":"101"}}'
- '== APP == Configuration for orderId2:{"orderId2":{"value":"102"}}'
- '== APP == App subscribed to config changes with subscription id:'
- '= APP == App unsubscribed from config changes'
- '== APP == Shutting down spring app'
- "Exited App successfully"
expected_stderr_lines:
output_match_mode: substring
match_order: none
-->
```bash
cd ./order-processor
dapr run --app-id order-processor --app-port 6001 --components-path ../../../components -- java -jar target/OrderProcessingService-0.0.1-SNAPSHOT.jar
```
<!-- END_STEP -->
## (Optional) Update value of config items
1. Keep the `order-processor` app running and open a separate terminal
2. Change the values of `orderId1` and `orderId2` using the command below
3. `order-processor` app gets the updated values of config items
<!-- STEP
name: Update config items
-->
```bash
docker exec dapr_redis redis-cli MSET orderId1 "103" orderId2 "104"
```
<!--END_STEP -->

View File

@ -0,0 +1,2 @@
include ../../../docker.mk
include ../../../validate.mk

View File

@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.6.3</version>
<relativePath/>
<!-- lookup parent from repository -->
</parent>
<groupId>com.service</groupId>
<artifactId>OrderProcessingService</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>OrderProcessingService</name>
<description>Demo for Dapr Configuration API</description>
<properties>
<java.version>11</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>20220924</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.6.4</version>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,113 @@
package com.service;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.json.*;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;
import java.util.Collections;
import java.util.List;
@SpringBootApplication
public class OrderProcessingServiceApplication {
private static final String DAPR_CONFIGURATION_STORE = "configstore";
private static List<String> CONFIGURATION_ITEMS = List.of("orderId1",
"orderId2");
private static String DAPR_HOST = System.getenv().getOrDefault("DAPR_HOST",
"http://localhost");
private static String DAPR_HTTP_PORT = System.getenv().getOrDefault("DAPR_HTTP_PORT", "3500");
private static String APP_PORT = System.getenv().getOrDefault("APP_PORT", "6001");
private static final HttpClient httpClient = HttpClient.newBuilder()
.version(HttpClient.Version.HTTP_2)
.connectTimeout(Duration.ofSeconds(10))
.build();
public static void main(String[] args) throws IOException, URISyntaxException, InterruptedException {
URI baseUrl = new URI(DAPR_HOST + ":" + DAPR_HTTP_PORT);
// Get config items from the config store
try {
for (String configurationItem : CONFIGURATION_ITEMS) {
URI uri = baseUrl
.resolve(
"/v1.0-alpha1/configuration/" + DAPR_CONFIGURATION_STORE + "?key=" +
configurationItem);
HttpRequest request = HttpRequest.newBuilder()
.GET()
.uri(uri)
.build();
HttpResponse<String> response = httpClient.send(request,
HttpResponse.BodyHandlers.ofString());
System.out.println("Configuration for " + configurationItem + ":" +
response.body());
}
} catch (Exception e) {
System.out.println("Could not get config item, err:" + e.getMessage());
System.exit(1);
}
// Create Spring Application to listen to configuration updates
SpringApplication app = new SpringApplication(OrderProcessingServiceApplication.class);
app.setDefaultProperties(Collections.singletonMap("server.port", APP_PORT));
// Start the application
ConfigurableApplicationContext context = app.run(args);
// Add delay to allow app channel to be ready
Thread.sleep(3000);
// Subscribe to Configuration Updates
String subscriptionId = null;
try {
URI uri = baseUrl
.resolve("/v1.0-alpha1/configuration/" + DAPR_CONFIGURATION_STORE + "/subscribe");
HttpRequest request = HttpRequest.newBuilder()
.GET()
.uri(uri)
.build();
HttpResponse<String> response = httpClient.send(request,
HttpResponse.BodyHandlers.ofString());
JSONObject subscription = new JSONObject(response.body());
subscriptionId = subscription.getString("id");
System.out.println("App subscribed to config changes with subscription id:" + subscriptionId);
} catch (Exception e) {
System.out.println("Error subscribing to config updates, err:" + e.getMessage());
System.exit(1);
}
// Receive config updates for 20 seconds, then unsubscribe from config updates and shutdown spring app
Thread.sleep(20000);
try {
// unsubscribe from config updates
URI uri = baseUrl
.resolve("/v1.0-alpha1/configuration/" + DAPR_CONFIGURATION_STORE + "/" + subscriptionId
+ "/unsubscribe");
HttpRequest request = HttpRequest.newBuilder()
.GET()
.uri(uri)
.build();
HttpResponse<String> response = httpClient.send(request,
HttpResponse.BodyHandlers.ofString());
if (response.body().contains("true")) {
System.out.println("App unsubscribed from config changes");
} else {
System.out.println("Error unsubscribing from config updates: " + response.body());
}
} catch (Exception e) {
System.out.println("Error unsubscribing from config updates, err:" + e.getMessage());
System.exit(1);
}
// Shutdown spring app
System.out.println("Shutting down spring app");
SpringApplication.exit(context, () -> 0);
System.exit(0);
}
}

View File

@ -0,0 +1,24 @@
package com.service.controller;
import java.util.Map;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class OrderProcessingServiceController {
/**
* Read configuration updates from config store
*
* @param body Request body
* @return ResponseEntity Returns ResponseEntity.ok()
*/
@PostMapping(path = "/configuration/configstore/{configItem}", consumes = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<?> readUpdates(@RequestBody Map<String, Object> body) {
System.out.println("Configuration update "+ body.get("items"));
return ResponseEntity.ok().build();
}
}

View File

@ -0,0 +1,89 @@
# Dapr Configuration API
In this quickstart, you'll create a microservice which makes use of Dapr's Configuration API. Configuration items are key/value pairs containing configuration data such as app ids, partition keys, database names etc. The service gets configuration items from the configuration store and subscribes for configuration updates.
Visit [this](https://docs.dapr.io/developing-applications/building-blocks/configuration/) link for more information about Dapr and Configuration API.
This quickstart includes one service:
- Java service `order-processor`
## Prerequisites
- [Maven 3.x](https://maven.apache.org/install.html)
- Java JDK 11 (or greater):
- [Microsoft JDK 11](https://docs.microsoft.com/en-us/java/openjdk/download#openjdk-11)
- [Oracle JDK 11](https://www.oracle.com/technetwork/java/javase/downloads/index.html#JDK11)
- [OpenJDK 11](https://jdk.java.net/11/)
- Locally running redis container - a redis container named `dapr_redis` is automatically created when you run `dapr init`
## Add configuration items to the config store
- Open a new terminal and set values for config items `orderId1` and `orderId2` by using the command below
<!-- STEP
name: Add configuration items
expected_stdout_lines:
- 'OK'
-->
```bash
docker exec dapr_redis redis-cli MSET orderId1 "101" orderId2 "102"
```
<!-- END_STEP -->
## Build the Java file
<!-- STEP
name: Build Java file
-->
```bash
cd ./order-processor
mvn clean install
```
<!-- END_STEP -->
## Run order-processor
1. Navigate to `order-processor` directory.
2. Run the service app with Dapr.
<!-- STEP
name: Run order-processor service
expected_stdout_lines:
- "== APP == Configuration for orderId1: {'value':'101'}"
- "== APP == Configuration for orderId2: {'value':'102'}"
- '== APP == App subscribed to config changes with subscription id:'
- '== APP == App unsubscribed to config changes'
- "Exited App successfully"
expected_stderr_lines:
output_match_mode: substring
match_order: none
-->
```bash
cd ./order-processor
dapr run --app-id order-processor --components-path ../../../components -- java -jar target/OrderProcessingService-0.0.1-SNAPSHOT.jar
```
<!-- END_STEP -->
## (Optional) Update value of config items
1. Keep the `order-processor` app running and open a separate terminal
2. Change the values of `orderId1` and `orderId2` using the command below
3. `order-processor` app gets the updated values of config items
<!-- STEP
name: Update config items
-->
```bash
docker exec dapr_redis redis-cli MSET orderId1 "103" orderId2 "104"
```
<!--END_STEP -->

View File

@ -0,0 +1,2 @@
include ../../../docker.mk
include ../../../validate.mk

View File

@ -0,0 +1,51 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.service</groupId>
<artifactId>OrderProcessingService</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>OrderProcessingService</name>
<description>Demo for Dapr Configuration API</description>
<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<slf4jVersion>1.6.1</slf4jVersion>
</properties>
<dependencies>
<dependency>
<groupId>io.dapr</groupId>
<artifactId>dapr-sdk</artifactId>
<version>1.7.1</version>
</dependency>
<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-core</artifactId>
<version>3.4.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.6.3</version>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
<configuration>
<mainClass>
com.service.OrderProcessingServiceApplication
</mainClass>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,60 @@
package com.service;
import io.dapr.client.DaprClientBuilder;
import io.dapr.client.DaprPreviewClient;
import io.dapr.client.domain.ConfigurationItem;
import io.dapr.client.domain.SubscribeConfigurationResponse;
import io.dapr.client.domain.UnsubscribeConfigurationResponse;
import reactor.core.publisher.Flux;
import java.util.List;
public class OrderProcessingServiceApplication {
private static final String DAPR_CONFIGURATON_STORE = "configstore";
private static List<String> CONFIGURATION_ITEMS = List.of("orderId1", "orderId2");
private static String subscriptionId = null;
public static void main(String[] args) throws Exception {
// Get config items from the config store
try (DaprPreviewClient client = (new DaprClientBuilder()).buildPreviewClient()) {
for (String configurationItem : CONFIGURATION_ITEMS) {
ConfigurationItem item = client.getConfiguration(DAPR_CONFIGURATON_STORE, configurationItem).block();
System.out.println("Configuration for " + configurationItem + ": {'value':'" + item.getValue() + "'}");
}
} catch (Exception e) {
System.out.println("Could not get config item, err:" + e.getMessage());
System.exit(1);
}
try (DaprPreviewClient client = (new DaprClientBuilder()).buildPreviewClient()) {
// Subscribe for config changes
Flux<SubscribeConfigurationResponse> subscription = client.subscribeConfiguration(DAPR_CONFIGURATON_STORE,
CONFIGURATION_ITEMS.toArray(String[]::new));
// 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);
// 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 reading config updates, err:" + e.getMessage());
System.exit(1);
}
}
}

View File

@ -0,0 +1,5 @@
##lint files
*.cjs
##node modules
node_modules

View File

@ -0,0 +1,83 @@
# Dapr Configuration API
In this quickstart, you'll create a microservice which makes use of Dapr's Configuration API. Configuration items are key/value pairs containing configuration data such as app ids, partition keys, database names etc. The service gets configuration items from the configuration store and subscribes for configuration updates.
Visit [this](https://docs.dapr.io/developing-applications/building-blocks/configuration/) link for more information about Dapr and Configuration API.
> **Note:** This example leverages HTTP `requests` only. If you are looking for the example using the Dapr Client SDK (recommended) [click here](../sdk/).
This quickstart includes one service:
- Node service `order-processor`
## Add configuration items to the config store
### Prerequisite
- Locally running redis container - a redis container named `dapr_redis` is automatically created when you run `dapr init`
- Open a new terminal and set values for config items `orderId1` and `orderId2` by using the command below
<!-- STEP
name: Add configuration items
expected_stdout_lines:
- 'OK'
-->
```bash
docker exec dapr_redis redis-cli MSET orderId1 "101" orderId2 "102"
```
<!-- END_STEP -->
## Run order-processor
1. Navigate to folder and install dependencies:
<!-- STEP
name: Install Node dependencies
-->
```bash
cd ./order-processor
npm install
```
<!-- END_STEP -->
1. Run the Node app with Dapr:
<!-- STEP
name: Run order-processor service
expected_stdout_lines:
- "== APP == Configuration for orderId1: { orderId1: { value: '101' } }"
- "== APP == Configuration for orderId2: { orderId2: { value: '102' } }"
- '== APP == App subscribed to config changes with subscription id:'
- '== APP == App unsubscribed from config changes'
- "Exited App successfully"
expected_stderr_lines:
output_match_mode: substring
match_order: none
-->
```bash
cd ./order-processor
dapr run --app-id order-processor --components-path ../../../components/ --app-port 6001 -- node index.js
```
<!-- END_STEP -->
## (Optional) Update value of config items
1. Keep the `order-processor` app running and open a separate terminal
2. Change the values of `orderId1` and `orderId2` using the command below
3. `order-processor` app gets the updated values of config items
<!-- STEP
name: Update config items
-->
```bash
docker exec dapr_redis redis-cli MSET orderId1 "103" orderId2 "104"
```
<!--END_STEP -->

View File

@ -0,0 +1,2 @@
include ../../../docker.mk
include ../../../validate.mk

View File

@ -0,0 +1,82 @@
import axios from "axios";
import express, { json } from "express";
const DAPR_HOST = process.env.DAPR_HOST ?? "localhost";
let DAPR_PORT = process.env.DAPR_HTTP_PORT ?? 3500;
let APP_PORT = process.env.APP_PORT ?? 6001;
const DAPR_CONFIGURATION_STORE = "configstore";
const BASE_URL = `http://${DAPR_HOST}:${DAPR_PORT}/v1.0-alpha1/configuration/${DAPR_CONFIGURATION_STORE}`;
const CONFIGURATION_ITEMS = ["orderId1", "orderId2"];
const app = express();
app.use(express.json());
async function main() {
// Get config items from the config store
CONFIGURATION_ITEMS.forEach((item) => {
axios
.get(`${BASE_URL}?key=${item}`)
.then((response) => {
console.log("Configuration for " + item + ":", response.data);
})
.catch((error) => {
console.log("Could not get config item, err:" + error);
process.exit(1);
});
});
// Start server to receive config updates
readConfigurationChanges();
// Subscribe to config updates
var subscriptionId = await subscribeToConfigUpdates();
// Unsubscribe to config updates and exit app after 20 seconds
setTimeout(async () => {
await unsubscribeToConfigUpdates(subscriptionId);
process.exit(0);
}, 20000);
}
async function subscribeToConfigUpdates() {
// Add delay to allow app channel to be ready
await sleep(3000);
// Subscribe to config updates
try {
const { data: response } = await axios.get(`${BASE_URL}/subscribe`);
console.log("App subscribed to config changes with subscription id: ", response.id);
return response.id;
} catch (error) {
console.log("Could not subscribe to config updates, err:" + error);
process.exit(1);
}
}
async function unsubscribeToConfigUpdates(subscriptionId) {
try {
const { data: response } = await axios.get(`${BASE_URL}/${subscriptionId}/unsubscribe`);
if (JSON.stringify(response).includes("true")) {
console.log("App unsubscribed from config changes");
} else {
console.log("Error unsubscribing to config updates, err:" + response);
}
} catch (error) {
console.log("Error unsubscribing to config updates, err:" + error);
}
}
async function readConfigurationChanges() {
// Create POST endpoint to receive config updates
app.post("/configuration/configstore/*", (req, res) => {
console.log("Configuration update", JSON.stringify(req.body.items));
res.sendStatus(200);
});
app.listen(APP_PORT, () => console.log("App listening for config updates"));
}
async function sleep(ms) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
main().catch((e) => console.error(e));

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,21 @@
{
"name": "order-processor",
"version": "1.0.0",
"description": "",
"main": "index.js",
"type": "module",
"scripts": {
"start": "node ."
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"axios": "^0.25.0",
"express": "^4.18.2"
},
"devDependencies": {
"eslint": "^8.8.0",
"eslint-plugin-react": "^7.28.0"
}
}

View File

@ -0,0 +1,5 @@
##lint files
*.cjs
##node modules
node_modules

View File

@ -0,0 +1,80 @@
# Dapr Configuration API
In this quickstart, you'll create a microservice which makes use of Dapr's Configuration API. Configuration items are key/value pairs containing configuration data such as app ids, partition keys, database names etc. The service gets configuration items from the configuration store and subscribes for configuration updates.
Visit [this](https://docs.dapr.io/developing-applications/building-blocks/configuration/) link for more information about Dapr and Configuration API.
This quickstart includes one service:
- Node service `order-processor`
## Add configuration items to the config store
### Prerequisite
- Locally running redis container - a redis container named `dapr_redis` is automatically created when you run `dapr init`
- Open a new terminal and set values for config items `orderId1` and `orderId2` by using the command below
<!-- STEP
name: Add configuration items
expected_stdout_lines:
- 'OK'
-->
```bash
docker exec dapr_redis redis-cli MSET orderId1 "101" orderId2 "102"
```
<!-- END_STEP -->
## Run order-processor
1. Navigate to folder and install dependencies:
<!-- STEP
name: Install Node dependencies
-->
```bash
cd ./order-processor
npm install
```
<!-- END_STEP -->
1. Run the Node app with Dapr:
<!-- STEP
name: Run order-processor service
expected_stdout_lines:
- '== APP == Configuration for orderId1: {"key":"orderId1","value":'
- '== APP == Configuration for orderId2: {"key":"orderId2","value":'
- '== APP == App unsubscribed to config changes'
- "Exited App successfully"
expected_stderr_lines:
output_match_mode: substring
match_order: none
-->
```bash
cd ./order-processor
dapr run --app-id order-processor --components-path ../../../components/ --app-protocol grpc --dapr-grpc-port 3500 -- node index.js
```
<!-- END_STEP -->
## (Optional) Update value of config items
1. Keep the `order-processor` app running and open a separate terminal
2. Change the values of `orderId1` and `orderId2` using the command below
3. `order-processor` app gets the updated values of config items
<!-- STEP
name: Update config items
-->
```bash
docker exec dapr_redis redis-cli MSET orderId1 "103" orderId2 "104"
```
<!--END_STEP -->

View File

@ -0,0 +1,2 @@
include ../../../docker.mk
include ../../../validate.mk

View File

@ -0,0 +1,44 @@
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);
}
// 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));

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,20 @@
{
"name": "order-processor",
"version": "1.0.0",
"description": "",
"main": "index.js",
"type": "module",
"scripts": {
"start": "node ."
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"@dapr/dapr": "^2.5.0"
},
"devDependencies": {
"eslint": "^8.8.0",
"eslint-plugin-react": "^7.28.0"
}
}

View File

@ -0,0 +1,82 @@
# Dapr Configuration API
In this quickstart, you'll create a microservice which makes use of Dapr's Configuration API. Configuration items are key/value pairs containing configuration data such as app ids, partition keys, database names etc. The service gets configuration items from the configuration store and subscribes for configuration updates.
Visit [this](https://docs.dapr.io/developing-applications/building-blocks/configuration/) link for more information about Dapr and Configuration API.
> **Note:** This example leverages HTTP `requests` only. If you are looking for the example using the Dapr Client SDK (recommended) [click here](../sdk/).
This quickstart includes one service:
- Python service `order-processor`
## Add configuration items to the config store
### Prerequisite
- Locally running redis container - a redis container named `dapr_redis` is automatically created when you run `dapr init`
- Open a new terminal and set values for config items `orderId1` and `orderId2` by using the command below
<!-- STEP
name: Add configuration items
expected_stdout_lines:
- 'OK'
-->
```bash
docker exec dapr_redis redis-cli MSET orderId1 "101" orderId2 "102"
```
<!-- END_STEP -->
## Run Python service with Dapr
1. Open a new terminal window and navigate to `order-processor` directory:
<!-- STEP
name: Install python dependencies
-->
```bash
cd ./order-processor
pip3 install -r requirements.txt
```
<!-- END_STEP -->
2. Run the Python service app with Dapr:
<!-- STEP
name: Run order-processor service
expected_stdout_lines:
- "== APP == INFO:root:Configuration for orderId1: {'orderId1': {'value': '101'}}"
- "== APP == INFO:root:Configuration for orderId2: {'orderId2': {'value': '102'}}"
- "== APP == INFO:root:App subscribed to config changes with subscription id:"
- 'App unsubscribed from config changes'
- "Exited App successfully"
expected_stderr_lines:
output_match_mode: substring
match_order: none
-->
```bash
cd ./order-processor
dapr run --app-id order-processor --components-path ../../../components/ --app-port 6001 -- python3 app.py
```
<!-- END_STEP -->
## (Optional) Update value of config items
1. Keep the `order-processor` app running and open a separate terminal
2. Change the values of `orderId1` and `orderId2` using the command below
3. `order-processor` app gets the updated values of config items
<!-- STEP
name: Update config items
-->
```bash
docker exec dapr_redis redis-cli MSET orderId1 "103" orderId2 "104"
```
<!--END_STEP -->

View File

@ -0,0 +1,2 @@
include ../../../docker.mk
include ../../../validate.mk

View File

@ -0,0 +1,59 @@
import threading
import time
import logging
import requests
import os
from flask import Flask, request
logging.basicConfig(level=logging.INFO)
app = Flask(__name__)
APP_PORT = os.getenv('APP_PORT', '6001')
BASE_URL = os.getenv('BASE_URL', 'http://localhost') + ':' + os.getenv(
'DAPR_HTTP_PORT', '3500')
DAPR_CONFIGURATION_STORE = 'configstore'
CONFIGURATION_ITEMS = ['orderId1', 'orderId2']
# Get config items from the config store
for item in CONFIGURATION_ITEMS:
config = requests.get(
url='%s/v1.0-alpha1/configuration/%s?key=%s' % (BASE_URL, DAPR_CONFIGURATION_STORE, item)
)
if config.status_code == 200:
logging.info('Configuration for ' +item+ ": " + str(config.json()))
else:
logging.info('Could not get config item, err: ' + str(config.json()))
def subscribe_config_updates():
# Add delay to allow app channel to be ready
time.sleep(3)
subscription = requests.get(
url = '%s/v1.0-alpha1/configuration/%s/subscribe' % (BASE_URL, DAPR_CONFIGURATION_STORE)
)
if subscription.status_code == 200 and 'errCode' not in str(subscription.json()) :
logging.info('App subscribed to config changes with subscription id: ' + str(subscription.json()['id']))
return subscription.json()['id']
else:
logging.info('Error subscribing to config updates: ' + str(subscription.json()))
exit(1)
# Create POST endpoint to receive config updates
@app.route('/configuration/configstore/<configItem>', methods=['POST'])
def config_subscriber(configItem):
print('Configuration update ' + str(request.json['items']), flush=True)
return '' , 200
# Start the flask app
threading.Thread(target=lambda: app.run(port=APP_PORT, debug=False, use_reloader=False), daemon=True).start()
# Subscribe to config updates
subscription_id = subscribe_config_updates()
# Unsubscribe to config updates and exit app after 20 seconds
time.sleep(20)
unsubscribe = requests.get(
url = '%s/v1.0-alpha1/configuration/%s/%s/unsubscribe' % (BASE_URL, DAPR_CONFIGURATION_STORE, subscription_id)
)
if unsubscribe.status_code == 200 and 'True' in str(unsubscribe.json()):
logging.info('App unsubscribed from config changes')
else:
logging.info('Error unsubscribing from config updates: ' + str(unsubscribe.json()))

View File

@ -0,0 +1,2 @@
requests
flask

View File

@ -0,0 +1,80 @@
# Dapr Configuration API
In this quickstart, you'll create a microservice which makes use of Dapr's Configuration API. Configuration items are key/value pairs containing configuration data such as app ids, partition keys, database names etc. The service gets configuration items from the configuration store and subscribes for configuration updates.
Visit [this](https://docs.dapr.io/developing-applications/building-blocks/configuration/) link for more information about Dapr and Configuration API.
This quickstart includes one service:
- Python service `order-processor`
## Add configuration items to the config store
### Prerequisite
- Locally running redis container - a redis container named `dapr_redis` is automatically created when you run `dapr init`
- Open a new terminal and set values for config items `orderId1` and `orderId2` by using the command below
<!-- STEP
name: Add configuration items
expected_stdout_lines:
- 'OK'
-->
```bash
docker exec dapr_redis redis-cli MSET orderId1 "101" orderId2 "102"
```
<!-- END_STEP -->
## Run Python service with Dapr
1. Open a new terminal window and navigate to `order-processor` directory:
<!-- STEP
name: Install python dependencies
-->
```bash
cd ./order-processor
pip3 install -r requirements.txt
```
<!-- END_STEP -->
2. Run the Python service app with Dapr:
<!-- STEP
name: Run order-processor service
expected_stdout_lines:
- '== APP == Configuration for orderId1 : value: "101"'
- '== APP == Configuration for orderId2 : value: "102"'
- '== APP == App unsubscribed from config changes'
- "Exited App successfully"
expected_stderr_lines:
output_match_mode: substring
match_order: none
-->
```bash
cd ./order-processor
dapr run --app-id order-processor --components-path ../../../components/ --app-port 6001 -- python3 app.py
```
<!-- END_STEP -->
## (Optional) Update value of config items
1. Keep the `order-processor` app running and open a separate terminal
2. Change the values of `orderId1` and `orderId2` using the command below
3. `order-processor` app gets the updated values of config items
<!-- STEP
name: Update config items
-->
```bash
docker exec dapr_redis redis-cli MSET orderId1 "103" orderId2 "104"
```
<!--END_STEP -->

View File

@ -0,0 +1,2 @@
include ../../../docker.mk
include ../../../validate.mk

View File

@ -0,0 +1,49 @@
import asyncio
import json
import threading
import time
import logging
from dapr.clients import DaprClient
from dapr.clients.grpc._response import ConfigurationWatcher
logging.basicConfig(level=logging.INFO)
configuration: ConfigurationWatcher = ConfigurationWatcher()
DAPR_CONFIGURATION_STORE = 'configstore'
CONFIGURATION_ITEMS = ['orderId1', 'orderId2']
with DaprClient() as client:
# Get config items from the config store
for config_item in CONFIGURATION_ITEMS:
config = client.get_configuration(store_name=DAPR_CONFIGURATION_STORE, keys=[config_item], config_metadata={})
print(f"Configuration for {config_item} : {config.items[config_item]}", flush=True)
async def subscribe_config():
with DaprClient() as client:
# Subscribe for configuration changes
configuration = await client.subscribe_configuration(DAPR_CONFIGURATION_STORE, CONFIGURATION_ITEMS)
# Exit app after 20 seconds
exitTime = time.time() + 20
while time.time() < exitTime:
if configuration is not None:
items = configuration.get_items()
for key in items:
print("Configuration update {'"+key+"' : {'value': '"+ items[key].value +"'}}", flush=True)
time.sleep(1)
# Unsubscribe from configuration updates
unsubscribed = True
for config_item in CONFIGURATION_ITEMS:
unsub_item = client.unsubscribe_configuration(DAPR_CONFIGURATION_STORE, config_item)
if unsub_item is False:
unsubscribed = False
if unsubscribed == True:
print("App unsubscribed from config changes", flush=True)
else:
print("Error unsubscribing from config updates", flush=True)
asyncio.run(subscribe_config())

View File

@ -0,0 +1 @@
dapr