From 49cb7f64ce182bbd2ef8057c205acb79f6ed7e9a Mon Sep 17 00:00:00 2001 From: tanvigour <> Date: Thu, 18 Nov 2021 16:49:56 +0530 Subject: [PATCH 01/30] add rel attribute to remove association with previous page --- daprdocs/layouts/partials/navbar.html | 2 +- daprdocs/layouts/partials/page-meta-links.html | 4 ++-- daprdocs/layouts/partials/version-banner.html | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/daprdocs/layouts/partials/navbar.html b/daprdocs/layouts/partials/navbar.html index e1dc682d4..5a2bc8fd6 100644 --- a/daprdocs/layouts/partials/navbar.html +++ b/daprdocs/layouts/partials/navbar.html @@ -14,7 +14,7 @@ {{ end }} {{ $url := urls.Parse .URL }} {{ $baseurl := urls.Parse $.Site.Params.Baseurl }} - {{ .Name }} + {{ .Name }} {{ end }} {{ if .Site.Params.versions }} diff --git a/daprdocs/layouts/partials/page-meta-links.html b/daprdocs/layouts/partials/page-meta-links.html index bd55efdf3..6bf0d95a1 100644 --- a/daprdocs/layouts/partials/page-meta-links.html +++ b/daprdocs/layouts/partials/page-meta-links.html @@ -21,8 +21,8 @@ {{ $newPageQS := querify "value" $newPageStub.Content "filename" "change-me.md" | safeURL }} {{ $newPageURL := printf "%s/new/%s?%s" $gh_repo $gh_repo_path $newPageQS }} - {{ T "post_edit_this" }} - {{ T "post_create_issue" }} + {{ T "post_edit_this" }} + {{ T "post_create_issue" }} {{ end }} {{ end }} diff --git a/daprdocs/layouts/partials/version-banner.html b/daprdocs/layouts/partials/version-banner.html index 0436da130..09b705b07 100644 --- a/daprdocs/layouts/partials/version-banner.html +++ b/daprdocs/layouts/partials/version-banner.html @@ -8,7 +8,7 @@ {{ with $current_version }}

The documentation you are viewing is for Dapr {{ . | markdownify }} which is an older version of Dapr. {{ with $latest_version }}For up-to-date documentation, see the - latest version.

+ latest version.

{{ end }} {{ end }} From 8901c9d6fe0d6559be1b0657ca751d8487f92fee Mon Sep 17 00:00:00 2001 From: Amulya Varote Date: Tue, 23 Nov 2021 02:52:27 -0800 Subject: [PATCH 02/30] State Management documentation --- .../howto-invoke-discover-services.md | 12 +- .../state-management/howto-get-save-state.md | 920 ++++++++++-------- 2 files changed, 547 insertions(+), 385 deletions(-) diff --git a/daprdocs/content/en/developing-applications/building-blocks/service-invocation/howto-invoke-discover-services.md b/daprdocs/content/en/developing-applications/building-blocks/service-invocation/howto-invoke-discover-services.md index 6e99d4a04..185d718ab 100644 --- a/daprdocs/content/en/developing-applications/building-blocks/service-invocation/howto-invoke-discover-services.md +++ b/daprdocs/content/en/developing-applications/building-blocks/service-invocation/howto-invoke-discover-services.md @@ -184,7 +184,7 @@ Below are code examples that leverage Dapr SDKs for service invocation. {{% codetab %}} ```csharp -//headers +//dependencies using Dapr.Client; using System.Net.Http; @@ -204,7 +204,7 @@ await client.InvokeMethodAsync(result); {{% codetab %}} ```java -//headers +//dependencies import io.dapr.client.DaprClient; import io.dapr.client.DaprClientBuilder; @@ -227,11 +227,11 @@ var result = daprClient.invokeMethod( {{% codetab %}} ```python -//headers +#dependencies from dapr.clients import DaprClient -//code +#code with DaprClient() as daprClient: result = daprClient.invoke_method( @@ -247,7 +247,7 @@ with DaprClient() as daprClient: {{% codetab %}} ```go -//headers +//dependencies import ( dapr "github.com/dapr/go-sdk/client" ) @@ -269,7 +269,7 @@ result, err := client.InvokeMethod(ctx, "checkout", "checkout/" + strconv.Itoa(o {{% codetab %}} ```javascript -//headers +//dependencies import { DaprClient, HttpMethod, CommunicationProtocolEnum } from 'dapr-client'; diff --git a/daprdocs/content/en/developing-applications/building-blocks/state-management/howto-get-save-state.md b/daprdocs/content/en/developing-applications/building-blocks/state-management/howto-get-save-state.md index d00c1ea61..e3a678037 100644 --- a/daprdocs/content/en/developing-applications/building-blocks/state-management/howto-get-save-state.md +++ b/daprdocs/content/en/developing-applications/building-blocks/state-management/howto-get-save-state.md @@ -19,6 +19,12 @@ In this guide we'll start of with the basics: Using the key/value state API to a - [Dapr CLI]({{< ref install-dapr-cli.md >}}) - Initialized [Dapr environment]({{< ref install-dapr-selfhost.md >}}) +## Example: + +The below code examples loosely describe an application that processes orders. In the examples, there is one service - an order processing service. This service has Dapr sidecar and the order processing service uses Dapr to store state in redis state store. + +Diagram showing state management of example service + ## Step 1: Setup a state store A state store component represents a resource that Dapr uses to communicate with a database. @@ -66,130 +72,210 @@ The following example shows how to a single key/value pair using the Dapr state It is important to set an app-id, as the state keys are prefixed with this value. If you don't set it one is generated for you at runtime, and the next time you run the command a new one will be generated and you will no longer be able to access previously saved state. {{% /alert %}} -{{< tabs "HTTP API (Bash)" "HTTP API (PowerShell)" "Python SDK" "PHP SDK">}} +Below are code examples that leverage Dapr SDKs for saving and retrieving a single state. -{{% codetab %}} -Begin by launching a Dapr sidecar: - -```bash -dapr run --app-id myapp --dapr-http-port 3500 -``` - -Then in a separate terminal save a key/value pair into your statestore: -```bash -curl -X POST -H "Content-Type: application/json" -d '[{ "key": "key1", "value": "value1"}]' http://localhost:3500/v1.0/state/statestore -``` - -Now get the state you just saved: -```bash -curl http://localhost:3500/v1.0/state/statestore/key1 -``` - -You can also restart your sidecar and try retrieving state again to see that state persists separate from the app. -{{% /codetab %}} +{{< tabs Dotnet Java Python Go Javascript "HTTP API (Bash)" "HTTP API (PowerShell)">}} {{% codetab %}} -Begin by launching a Dapr sidecar: +```csharp +//dependencies + +using Dapr.Client; + +//code + +string DAPR_STORE_NAME = "statestore"; + +using var client = new DaprClientBuilder().Build(); +await client.SaveStateAsync(DAPR_STORE_NAME, "order_1", orderId.ToString()); +var result = await client.GetStateAsync(DAPR_STORE_NAME, orderId.ToString()); +Console.WriteLine("Result after get: " + result); + +``` + +Once saved run the following command to launch a Dapr sidecar and run the application: ```bash -dapr --app-id myapp --port 3500 run +dapr run --app-id orderprocessing --app-port 6001 --dapr-http-port 3601 --dapr-grpc-port 60001 dotnet run ``` -Then in a separate terminal save a key/value pair into your statestore: -```powershell -Invoke-RestMethod -Method Post -ContentType 'application/json' -Body '[{"key": "key1", "value": "value1"}]' -Uri 'http://localhost:3500/v1.0/state/statestore' -``` - -Now get the state you just saved: -```powershell -Invoke-RestMethod -Uri 'http://localhost:3500/v1.0/state/statestore/key1' -``` - -You can also restart your sidecar and try retrieving state again to see that state persists separate from the app. - {{% /codetab %}} + + {{% codetab %}} -Save the following to a file named `pythonState.py`: +```java +//dependencies + +import io.dapr.client.DaprClient; +import io.dapr.client.DaprClientBuilder; + +//code + +private static final String STATE_STORE_NAME = "statestore"; + +DaprClient client = new DaprClientBuilder().build(); +client.saveState(STATE_STORE_NAME, "order_1", Integer.toString(orderId)).block(); +Mono> result = client.getState(STATE_STORE_NAME, "order_1", String.class); +log.info("Result after get" + result); + +``` + +Once saved run the following command to launch a Dapr sidecar and run the application: + +```bash +dapr run --app-id orderprocessing --app-port 6001 --dapr-http-port 3601 --dapr-grpc-port 60001 mvn spring-boot:run +``` + +{{% /codetab %}} + + +{{% codetab %}} ```python +#dependencies + from dapr.clients import DaprClient -with DaprClient() as d: - d.save_state(store_name="statestore", key="myFirstKey", value="myFirstValue" ) - print("State has been stored") +#code - data = d.get_state(store_name="statestore", key="myFirstKey").data - print(f"Got value: {data}") +DAPR_STORE_NAME = "statestore" + +with DaprClient() as client: + client.save_state(DAPR_STORE_NAME, "order_1", str(orderId)) + result = client.get_state(DAPR_STORE_NAME, "order_1") + logging.info('Result after get: ' + str(result)) ``` -Once saved run the following command to launch a Dapr sidecar and run the Python application: +Once saved run the following command to launch a Dapr sidecar and run the application: ```bash -dapr --app-id myapp run python pythonState.py -``` - -You should get an output similar to the following, which will show both the Dapr and app logs: - -```md -== DAPR == time="2021-01-06T21:34:33.7970377-08:00" level=info msg="starting Dapr Runtime -- version 0.11.3 -- commit a1a8e11" app_id=Braidbald-Boot scope=dapr.runtime type=log ver=0.11.3 -== DAPR == time="2021-01-06T21:34:33.8040378-08:00" level=info msg="standalone mode configured" app_id=Braidbald-Boot scope=dapr.runtime type=log ver=0.11.3 -== DAPR == time="2021-01-06T21:34:33.8040378-08:00" level=info msg="app id: Braidbald-Boot" app_id=Braidbald-Boot scope=dapr.runtime type=log ver=0.11.3 -== DAPR == time="2021-01-06T21:34:33.9750400-08:00" level=info msg="component loaded. name: statestore, type: state.redis" app_id=Braidbald-Boot scope=dapr.runtime type=log ver=0.11.3 -== DAPR == time="2021-01-06T21:34:33.9760387-08:00" level=info msg="API gRPC server is running on port 51656" app_id=Braidbald-Boot scope=dapr.runtime type=log ver=0.11.3 -== DAPR == time="2021-01-06T21:34:33.9770372-08:00" level=info msg="dapr initialized. Status: Running. Init Elapsed 172.9994ms" app_id=Braidbald-Boot scope=dapr. - -Checking if Dapr sidecar is listening on GRPC port 51656 -Dapr sidecar is up and running. -Updating metadata for app command: python pythonState.py -You are up and running! Both Dapr and your app logs will appear here. - -== APP == State has been stored -== APP == Got value: b'myFirstValue' +dapr run --app-id orderprocessing --app-port 6001 --dapr-http-port 3601 --dapr-grpc-port 60001 -- python3 OrderProcessingService.py ``` {{% /codetab %}} + {{% codetab %}} -Save the following in `state-example.php`: +```go +//dependencies -```php -run(function(\Dapr\State\StateManager $stateManager, \Psr\Log\LoggerInterface $logger) { - $stateManager->save_state(store_name: 'statestore', item: new \Dapr\State\StateItem( - key: 'myFirstKey', - value: 'myFirstValue' - )); - $logger->alert('State has been stored'); - $data = $stateManager->load_state(store_name: 'statestore', key: 'myFirstKey')->value; - $logger->alert("Got value: {data}", ['data' => $data]); -}); ``` -Once saved run the following command to launch a Dapr sidecar and run the PHP application: +Once saved run the following command to launch a Dapr sidecar and run the application: ```bash -dapr --app-id myapp run -- php state-example.php +dapr run --app-id orderprocessing --app-port 6001 --dapr-http-port 3601 --dapr-grpc-port 60001 go run OrderProcessingService.go ``` -You should get an output similar to the following, which will show both the Dapr and app logs: +{{% /codetab %}} -```md -✅ You're up and running! Both Dapr and your app logs will appear here. -== APP == [2021-02-12T16:30:11.078777+01:00] APP.ALERT: State has been stored [] [] +{{% codetab %}} + +```javascript +//dependencies + +import { DaprClient, HttpMethod, CommunicationProtocolEnum } from 'dapr-client'; + +//code + +const STATE_STORE_NAME = "statestore"; + +const daprHost = "127.0.0.1"; +const client = new DaprClient(daprHost, process.env.DAPR_HTTP_PORT, CommunicationProtocolEnum.HTTP); +await client.state.save(STATE_STORE_NAME, [ +{ + key: "order_1", + value: orderId.toString() +}]); +var result = await client.state.get(STATE_STORE_NAME, "order_1"); +console.log("Result after get: " + result); + -== APP == [2021-02-12T16:30:11.082620+01:00] APP.ALERT: Got value: myFirstValue {"data":"myFirstValue"} [] ``` +Once saved run the following command to launch a Dapr sidecar and run the application: + +```bash +dapr run --app-id orderprocessing --app-port 6001 --dapr-http-port 3601 --dapr-grpc-port 60001 npm start +``` + +{{% /codetab %}} + + +{{% codetab %}} +Begin by launching a Dapr sidecar: + +```bash +dapr run --app-id orderprocessing --dapr-http-port 3601 +``` + +Then in a separate terminal save a key/value pair into your statestore: +```bash +curl -X POST -H "Content-Type: application/json" -d '[{ "key": "order_1", "value": "250"}]' http://localhost:3601/v1.0/state/statestore +``` + +Now get the state you just saved: +```bash +curl http://localhost:3601/v1.0/state/statestore/order_1 +``` + +You can also restart your sidecar and try retrieving state again to see that state persists separate from the app. +{{% /codetab %}} + +{{% codetab %}} + +Begin by launching a Dapr sidecar: + +```bash +dapr --app-id orderprocessing --port 3601 run +``` + +Then in a separate terminal save a key/value pair into your statestore: +```powershell +Invoke-RestMethod -Method Post -ContentType 'application/json' -Body '[{"key": "order_1", "value": "250"}]' -Uri 'http://localhost:3601/v1.0/state/statestore' +``` + +Now get the state you just saved: +```powershell +Invoke-RestMethod -Uri 'http://localhost:3601/v1.0/state/statestore/order_1' +``` + +You can also restart your sidecar and try retrieving state again to see that state persists separate from the app. + {{% /codetab %}} {{< /tabs >}} @@ -197,14 +283,150 @@ You should get an output similar to the following, which will show both the Dapr ## Step 3: Delete state -The following example shows how to delete an item by using a key with the state management API: +Below are code examples that leverage Dapr SDKs for deleting the state. -{{< tabs "HTTP API (Bash)" "HTTP API (PowerShell)" "Python SDK" "PHP SDK">}} +{{< tabs Dotnet Java Python Go Javascript "HTTP API (Bash)" "HTTP API (PowerShell)">}} + +{{% codetab %}} + +```csharp +//dependencies + +using Dapr.Client; + +//code + +string DAPR_STORE_NAME = "statestore"; + +await client.DeleteStateAsync(DAPR_STORE_NAME, "order_1", cancellationToken: cancellationToken); + +``` + +Once saved run the following command to launch a Dapr sidecar and run the application: + +```bash +dapr run --app-id orderprocessing --app-port 6001 --dapr-http-port 3601 --dapr-grpc-port 60001 dotnet run +``` + +{{% /codetab %}} + + +{{% codetab %}} + +```java +//dependencies + +import io.dapr.client.DaprClient; +import io.dapr.client.DaprClientBuilder; + +//code + +private static final String STATE_STORE_NAME = "statestore"; + +DaprClient client = new DaprClientBuilder().build(); +String storedEtag = client.getState(STATE_STORE_NAME, "order_1", String.class).block().getEtag(); +client.deleteState(STATE_STORE_NAME, "order_1", storedEtag, null).block(); + +``` + +Once saved run the following command to launch a Dapr sidecar and run the application: + +```bash +dapr run --app-id orderprocessing --app-port 6001 --dapr-http-port 3601 --dapr-grpc-port 60001 mvn spring-boot:run +``` + +{{% /codetab %}} + + +{{% codetab %}} + +```python +#dependencies + +from dapr.clients import DaprClient + +#code + +DAPR_STORE_NAME = "statestore" + +with DaprClient() as client: + client.delete_state(store_name=DAPR_STORE_NAME, key="order_1") + +``` + +Once saved run the following command to launch a Dapr sidecar and run the application: + +```bash +dapr run --app-id orderprocessing --app-port 6001 --dapr-http-port 3601 --dapr-grpc-port 60001 -- python3 OrderProcessingService.py +``` + +{{% /codetab %}} + + +{{% codetab %}} + +```go +//dependencies + +import ( + dapr "github.com/dapr/go-sdk/client" +) + +//code + +client, err := dapr.NewClient() +STATE_STORE_NAME := "statestore" + +if err != nil { + panic(err) +} +defer client.Close() +ctx := context.Background() + +if err := client.DeleteState(ctx, store, "order_1"); err != nil { + panic(err) +} + +``` + +Once saved run the following command to launch a Dapr sidecar and run the application: + +```bash +dapr run --app-id orderprocessing --app-port 6001 --dapr-http-port 3601 --dapr-grpc-port 60001 go run OrderProcessingService.go +``` + +{{% /codetab %}} + + +{{% codetab %}} + +```javascript +//dependencies + +import { DaprClient, HttpMethod, CommunicationProtocolEnum } from 'dapr-client'; + +//code + +const STATE_STORE_NAME = "statestore"; + +const client = new DaprClient(daprHost, process.env.DAPR_HTTP_PORT, CommunicationProtocolEnum.HTTP); +await client.state.delete(STATE_STORE_NAME, "order_1"); + + +``` + +Once saved run the following command to launch a Dapr sidecar and run the application: + +```bash +dapr run --app-id orderprocessing --app-port 6001 --dapr-http-port 3601 --dapr-grpc-port 60001 npm start +``` + +{{% /codetab %}} {{% codetab %}} With the same dapr instance running from above run: ```bash -curl -X DELETE 'http://localhost:3500/v1.0/state/statestore/key1' +curl -X DELETE 'http://localhost:3601/v1.0/state/statestore/order_1' ``` Try getting state again and note that no value is returned. {{% /codetab %}} @@ -212,228 +434,134 @@ Try getting state again and note that no value is returned. {{% codetab %}} With the same dapr instance running from above run: ```powershell -Invoke-RestMethod -Method Delete -Uri 'http://localhost:3500/v1.0/state/statestore/key1' +Invoke-RestMethod -Method Delete -Uri 'http://localhost:3601/v1.0/state/statestore/order_1' ``` Try getting state again and note that no value is returned. {{% /codetab %}} -{{% codetab %}} - -Update `pythonState.py` with: - -```python -from dapr.clients import DaprClient - -with DaprClient() as d: - d.save_state(store_name="statestore", key="key1", value="value1" ) - print("State has been stored") - - data = d.get_state(store_name="statestore", key="key1").data - print(f"Got value: {data}") - - d.delete_state(store_name="statestore", key="key1") - - data = d.get_state(store_name="statestore", key="key1").data - print(f"Got value after delete: {data}") -``` - -Now run your program with: - -```bash -dapr --app-id myapp run python pythonState.py -``` - -You should see an output similar to the following: - -```md -Starting Dapr with id Yakchocolate-Lord. HTTP Port: 59457. gRPC Port: 59458 - -== DAPR == time="2021-01-06T22:55:36.5570696-08:00" level=info msg="starting Dapr Runtime -- version 0.11.3 -- commit a1a8e11" app_id=Yakchocolate-Lord scope=dapr.runtime type=log ver=0.11.3 -== DAPR == time="2021-01-06T22:55:36.5690367-08:00" level=info msg="standalone mode configured" app_id=Yakchocolate-Lord scope=dapr.runtime type=log ver=0.11.3 -== DAPR == time="2021-01-06T22:55:36.7220140-08:00" level=info msg="component loaded. name: statestore, type: state.redis" app_id=Yakchocolate-Lord scope=dapr.runtime type=log ver=0.11.3 -== DAPR == time="2021-01-06T22:55:36.7230148-08:00" level=info msg="API gRPC server is running on port 59458" app_id=Yakchocolate-Lord scope=dapr.runtime type=log ver=0.11.3 -== DAPR == time="2021-01-06T22:55:36.7240207-08:00" level=info msg="dapr initialized. Status: Running. Init Elapsed 154.984ms" app_id=Yakchocolate-Lord scope=dapr.runtime type=log ver=0.11.3 - -Checking if Dapr sidecar is listening on GRPC port 59458 -Dapr sidecar is up and running. -Updating metadata for app command: python pythonState.py -You're up and running! Both Dapr and your app logs will appear here. - -== APP == State has been stored -== APP == Got value: b'value1' -== APP == Got value after delete: b'' -``` -{{% /codetab %}} - -{{% codetab %}} - -Update `state-example.php` with the following contents: - -```php -run(function(\Dapr\State\StateManager $stateManager, \Psr\Log\LoggerInterface $logger) { - $stateManager->save_state(store_name: 'statestore', item: new \Dapr\State\StateItem( - key: 'myFirstKey', - value: 'myFirstValue' - )); - $logger->alert('State has been stored'); - - $data = $stateManager->load_state(store_name: 'statestore', key: 'myFirstKey')->value; - $logger->alert("Got value: {data}", ['data' => $data]); - - $stateManager->delete_keys(store_name: 'statestore', keys: ['myFirstKey']); - $data = $stateManager->load_state(store_name: 'statestore', key: 'myFirstKey')->value; - $logger->alert("Got value after delete: {data}", ['data' => $data]); -}); -``` - -Now run it with: - -```bash -dapr --app-id myapp run -- php state-example.php -``` - -You should see something similar the following output: - -```md -✅ You're up and running! Both Dapr and your app logs will appear here. - -== APP == [2021-02-12T16:38:00.839201+01:00] APP.ALERT: State has been stored [] [] - -== APP == [2021-02-12T16:38:00.841997+01:00] APP.ALERT: Got value: myFirstValue {"data":"myFirstValue"} [] - -== APP == [2021-02-12T16:38:00.845721+01:00] APP.ALERT: Got value after delete: {"data":null} [] -``` - -{{% /codetab %}} - {{< /tabs >}} ## Step 4: Save and retrieve multiple states -Dapr also allows you to save and retrieve multiple states in the same call. +Below are code examples that leverage Dapr SDKs for saving and retrieving multiple states. -{{< tabs "HTTP API (Bash)" "HTTP API (PowerShell)" "Python SDK" "PHP SDK">}} +{{< tabs Java Python Javascript "HTTP API (Bash)" "HTTP API (PowerShell)">}} {{% codetab %}} -With the same dapr instance running from above save two key/value pairs into your statestore: + +```java +//dependencies + +import io.dapr.client.DaprClient; +import io.dapr.client.DaprClientBuilder; +import reactor.core.publisher.Mono; +import io.dapr.client.domain.State; +import java.util.List; + +//code + +private static final String STATE_STORE_NAME = "statestore"; + +DaprClient client = new DaprClientBuilder().build(); +Mono>> resultBulk = client.getBulkState(STATE_STORE_NAME, + Arrays.asList("order_1", "order_2"), String.class); +log.info("Result after get bulk" + resultBulk); + +``` + +Once saved run the following command to launch a Dapr sidecar and run the application: + ```bash -curl -X POST -H "Content-Type: application/json" -d '[{ "key": "key1", "value": "value1"}, { "key": "key2", "value": "value2"}]' http://localhost:3500/v1.0/state/statestore -``` - -Now get the states you just saved: -```bash -curl -X POST -H "Content-Type: application/json" -d '{"keys":["key1", "key2"]}' http://localhost:3500/v1.0/state/statestore/bulk -``` -{{% /codetab %}} - -{{% codetab %}} -With the same dapr instance running from above save two key/value pairs into your statestore: -```powershell -Invoke-RestMethod -Method Post -ContentType 'application/json' -Body '[{ "key": "key1", "value": "value1"}, { "key": "key2", "value": "value2"}]' -Uri 'http://localhost:3500/v1.0/state/statestore' -``` - -Now get the states you just saved: -```powershell -Invoke-RestMethod -Method Post -ContentType 'application/json' -Body '{"keys":["key1", "key2"]}' -Uri 'http://localhost:3500/v1.0/state/statestore/bulk' +dapr run --app-id orderprocessing --app-port 6001 --dapr-http-port 3601 --dapr-grpc-port 60001 mvn spring-boot:run ``` {{% /codetab %}} + {{% codetab %}} -The `StateItem` object can be used to store multiple Dapr states with the `save_states` and `get_states` methods. - -Update your `pythonState.py` file with the following code: - ```python +#dependencies + from dapr.clients import DaprClient from dapr.clients.grpc._state import StateItem -with DaprClient() as d: - s1 = StateItem(key="key1", value="value1") - s2 = StateItem(key="key2", value="value2") +#code - d.save_bulk_state(store_name="statestore", states=[s1,s2]) - print("States have been stored") +DAPR_STORE_NAME = "statestore" + +with DaprClient() as client: + client.save_bulk_state(store_name=DAPR_STORE_NAME, states=[StateItem(key="order_2", value=str(orderId))]) + result = client.get_bulk_state(store_name=DAPR_STORE_NAME, keys=["order_1", "order_2"], states_metadata={"metakey": "metavalue"}).items + logging.info('Result after get bulk: ' + str(result)) - items = d.get_bulk_state(store_name="statestore", keys=["key1", "key2"]).items - print(f"Got items: {[i.data for i in items]}") ``` -Now run your program with: +Once saved run the following command to launch a Dapr sidecar and run the application: ```bash -dapr --app-id myapp run python pythonState.py +dapr run --app-id orderprocessing --app-port 6001 --dapr-http-port 3601 --dapr-grpc-port 60001 -- python3 OrderProcessingService.py ``` -You should see an output similar to the following: +{{% /codetab %}} -```md -== DAPR == time="2021-01-06T21:54:56.7262358-08:00" level=info msg="starting Dapr Runtime -- version 0.11.3 -- commit a1a8e11" app_id=Musesequoia-Sprite scope=dapr.runtime type=log ver=0.11.3 -== DAPR == time="2021-01-06T21:54:56.7401933-08:00" level=info msg="standalone mode configured" app_id=Musesequoia-Sprite scope=dapr.runtime type=log ver=0.11.3 -== DAPR == time="2021-01-06T21:54:56.8754240-08:00" level=info msg="Initialized name resolution to standalone" app_id=Musesequoia-Sprite scope=dapr.runtime type=log ver=0.11.3 -== DAPR == time="2021-01-06T21:54:56.8844248-08:00" level=info msg="component loaded. name: statestore, type: state.redis" app_id=Musesequoia-Sprite scope=dapr.runtime type=log ver=0.11.3 -== DAPR == time="2021-01-06T21:54:56.8854273-08:00" level=info msg="API gRPC server is running on port 60614" app_id=Musesequoia-Sprite scope=dapr.runtime type=log ver=0.11.3 -== DAPR == time="2021-01-06T21:54:56.8854273-08:00" level=info msg="dapr initialized. Status: Running. Init Elapsed 145.234ms" app_id=Musesequoia-Sprite scope=dapr.runtime type=log ver=0.11.3 -Checking if Dapr sidecar is listening on GRPC port 60614 -Dapr sidecar is up and running. -Updating metadata for app command: python pythonState.py -You're up and running! Both Dapr and your app logs will appear here. -== APP == States have been stored -== APP == Got items: [b'value1', b'value2'] +{{% codetab %}} + +```javascript +//dependencies + +import { DaprClient, HttpMethod, CommunicationProtocolEnum } from 'dapr-client'; + +//code + +const client = new DaprClient(daprHost, process.env.DAPR_HTTP_PORT, CommunicationProtocolEnum.HTTP); +const STATE_STORE_NAME = "statestore"; +await client.state.save(STATE_STORE_NAME, [ + { + key: "order_1", + value: orderId.toString() + }, + { + key: "order_2", + value: orderId.toString() + } +]); +result = await client.state.getBulk(STATE_STORE_NAME, ["order_1", "order_2"]); +console.log("Result after get bulk: " + result); + +``` + +Once saved run the following command to launch a Dapr sidecar and run the application: + +```bash +dapr run --app-id orderprocessing --app-port 6001 --dapr-http-port 3601 --dapr-grpc-port 60001 npm start ``` {{% /codetab %}} {{% codetab %}} - -To batch load and save state with PHP, just create a "Plain Ole' PHP Object" (POPO) and annotate it with -the StateStore annotation. - -Update the `state-example.php` file: - -```php -run(function(\Dapr\State\StateManager $stateManager, \Psr\Log\LoggerInterface $logger) { - $obj = new MyState(); - $stateManager->save_object(item: $obj); - $logger->alert('States have been stored'); - - $stateManager->load_object(into: $obj); - $logger->alert("Got value: {data}", ['data' => $obj]); -}); -``` - -Run the app: - +With the same dapr instance running from above save two key/value pairs into your statestore: ```bash -dapr --app-id myapp run -- php state-example.php +curl -X POST -H "Content-Type: application/json" -d '[{ "key": "order_1", "value": "250"}, { "key": "order_2", "value": "550"}]' http://localhost:3601/v1.0/state/statestore ``` -And see the following output: +Now get the states you just saved: +```bash +curl -X POST -H "Content-Type: application/json" -d '{"keys":["order_1", "order_2"]}' http://localhost:3601/v1.0/state/statestore/bulk +``` +{{% /codetab %}} -```md -✅ You're up and running! Both Dapr and your app logs will appear here. +{{% codetab %}} +With the same dapr instance running from above save two key/value pairs into your statestore: +```powershell +Invoke-RestMethod -Method Post -ContentType 'application/json' -Body '[{ "key": "order_1", "value": "250"}, { "key": "order_2", "value": "550"}]' -Uri 'http://localhost:3601/v1.0/state/statestore' +``` -== APP == [2021-02-12T16:55:02.913801+01:00] APP.ALERT: States have been stored [] [] - -== APP == [2021-02-12T16:55:02.917850+01:00] APP.ALERT: Got value: [object MyState] {"data":{"MyState":{"key1":"value1","key2":"value2"}}} [] +Now get the states you just saved: +```powershell +Invoke-RestMethod -Method Post -ContentType 'application/json' -Body '{"keys":["order_1", "order_2"]}' -Uri 'http://localhost:3601/v1.0/state/statestore/bulk' ``` {{% /codetab %}} @@ -446,138 +574,172 @@ And see the following output: State transactions require a state store that supports multi-item transactions. Visit the [supported state stores page]({{< ref supported-state-stores >}}) page for a full list. Note that the default Redis container created in a self-hosted environment supports them. {{% /alert %}} -{{< tabs "HTTP API (Bash)" "HTTP API (PowerShell)" "Python SDK" "PHP SDK">}} +Below are code examples that leverage Dapr SDKs for performing state transactions. + +{{< tabs Dotnet Java Python Javascript "HTTP API (Bash)" "HTTP API (PowerShell)">}} + +{{% codetab %}} + +```csharp +//dependencies + +using Dapr.Client; + +//code + +string DAPR_STORE_NAME = "statestore"; +using var client = new DaprClientBuilder().Build(); +var requests = new List() +{ + new StateTransactionRequest("order_3", JsonSerializer.SerializeToUtf8Bytes(orderId.ToString()), StateOperationType.Upsert), + new StateTransactionRequest("order_2", null, StateOperationType.Delete) +}; + +CancellationTokenSource source = new CancellationTokenSource(); +CancellationToken cancellationToken = source.Token; + +await client.ExecuteStateTransactionAsync(DAPR_STORE_NAME, requests, cancellationToken: cancellationToken); + +``` + +Once saved run the following command to launch a Dapr sidecar and run the application: + +```bash +dapr run --app-id orderprocessing --app-port 6001 --dapr-http-port 3601 --dapr-grpc-port 60001 dotnet run +``` + +{{% /codetab %}} + + +{{% codetab %}} + +```java +//dependencies + +import io.dapr.client.DaprClient; +import io.dapr.client.DaprClientBuilder; +import io.dapr.client.domain.State; +import io.dapr.client.domain.TransactionalStateOperation; + +//code + +private static final String STATE_STORE_NAME = "statestore"; + +DaprClient client = new DaprClientBuilder().build(); +List> operationList = new ArrayList<>(); +operationList.add(new TransactionalStateOperation<>(TransactionalStateOperation.OperationType.UPSERT, + new State<>("order_3", Integer.toString(orderId), ""))); +operationList.add(new TransactionalStateOperation<>(TransactionalStateOperation.OperationType.DELETE, + new State<>("order_2"))); +client.executeStateTransaction(STATE_STORE_NAME, operationList).block(); + +``` + +Once saved run the following command to launch a Dapr sidecar and run the application: + +```bash +dapr run --app-id orderprocessing --app-port 6001 --dapr-http-port 3601 --dapr-grpc-port 60001 mvn spring-boot:run +``` + +{{% /codetab %}} + + +{{% codetab %}} + +```python +#dependencies + +from dapr.clients import DaprClient +from dapr.clients.grpc._state import StateItem +from dapr.clients.grpc._request import TransactionalStateOperation, TransactionOperationType + +#code + +DAPR_STORE_NAME = "statestore" +with DaprClient() as client: + client.execute_state_transaction(store_name=DAPR_STORE_NAME, operations=[ + TransactionalStateOperation( + operation_type=TransactionOperationType.upsert, + key="order_3", + data=str(orderId)), + TransactionalStateOperation(key="order_3", data=str(orderId)), + TransactionalStateOperation( + operation_type=TransactionOperationType.delete, + key="order_2", + data=str(orderId)), + TransactionalStateOperation(key="order_2", data=str(orderId)) + ]) + +``` + +Once saved run the following command to launch a Dapr sidecar and run the application: + +```bash +dapr run --app-id orderprocessing --app-port 6001 --dapr-http-port 3601 --dapr-grpc-port 60001 -- python3 OrderProcessingService.py +``` + +{{% /codetab %}} + + +{{% codetab %}} + +```javascript +//dependencies + +import { DaprClient, HttpMethod, CommunicationProtocolEnum } from 'dapr-client'; + + +//code + +const STATE_STORE_NAME = "statestore"; +const client = new DaprClient(daprHost, process.env.DAPR_HTTP_PORT, CommunicationProtocolEnum.HTTP); +await client.state.transaction(STATE_STORE_NAME, [ + { + operation: "upsert", + request: { + key: "order_3", + value: orderId.toString() + } + }, + { + operation: "delete", + request: { + key: "order_2" + } + } +]); + +``` + +Once saved run the following command to launch a Dapr sidecar and run the application: + +```bash +dapr run --app-id orderprocessing --app-port 6001 --dapr-http-port 3601 --dapr-grpc-port 60001 npm start +``` + +{{% /codetab %}} {{% codetab %}} With the same dapr instance running from above perform two state transactions: ```bash -curl -X POST -H "Content-Type: application/json" -d '{"operations": [{"operation":"upsert", "request": {"key": "key1", "value": "newValue1"}}, {"operation":"delete", "request": {"key": "key2"}}]}' http://localhost:3500/v1.0/state/statestore/transaction +curl -X POST -H "Content-Type: application/json" -d '{"operations": [{"operation":"upsert", "request": {"key": "order_1", "value": "250"}}, {"operation":"delete", "request": {"key": "order_2"}}]}' http://localhost:3601/v1.0/state/statestore/transaction ``` Now see the results of your state transactions: ```bash -curl -X POST -H "Content-Type: application/json" -d '{"keys":["key1", "key2"]}' http://localhost:3500/v1.0/state/statestore/bulk +curl -X POST -H "Content-Type: application/json" -d '{"keys":["order_1", "order_2"]}' http://localhost:3601/v1.0/state/statestore/bulk ``` {{% /codetab %}} {{% codetab %}} With the same dapr instance running from above save two key/value pairs into your statestore: ```powershell -Invoke-RestMethod -Method Post -ContentType 'application/json' -Body '{"operations": [{"operation":"upsert", "request": {"key": "key1", "value": "newValue1"}}, {"operation":"delete", "request": {"key": "key2"}}]}' -Uri 'http://localhost:3500/v1.0/state/statestore' +Invoke-RestMethod -Method Post -ContentType 'application/json' -Body '{"operations": [{"operation":"upsert", "request": {"key": "order_1", "value": "250"}}, {"operation":"delete", "request": {"key": "order_2"}}]}' -Uri 'http://localhost:3601/v1.0/state/statestore' ``` Now see the results of your state transactions: ```powershell -Invoke-RestMethod -Method Post -ContentType 'application/json' -Body '{"keys":["key1", "key2"]}' -Uri 'http://localhost:3500/v1.0/state/statestore/bulk' -``` - -{{% /codetab %}} - -{{% codetab %}} - -The `TransactionalStateOperation` can perform a state transaction if your state stores need to be transactional. - -Update your `pythonState.py` file with the following code: - -```python -from dapr.clients import DaprClient -from dapr.clients.grpc._state import StateItem -from dapr.clients.grpc._request import TransactionalStateOperation, TransactionOperationType - -with DaprClient() as d: - s1 = StateItem(key="key1", value="value1") - s2 = StateItem(key="key2", value="value2") - - d.save_bulk_state(store_name="statestore", states=[s1,s2]) - print("States have been stored") - - d.execute_state_transaction( - store_name="statestore", - operations=[ - TransactionalStateOperation(key="key1", data="newValue1", operation_type=TransactionOperationType.upsert), - TransactionalStateOperation(key="key2", data="value2", operation_type=TransactionOperationType.delete) - ] - ) - print("State transactions have been completed") - - items = d.get_bulk_state(store_name="statestore", keys=["key1", "key2"]).items - print(f"Got items: {[i.data for i in items]}") -``` - -Now run your program with: - -```bash -dapr run python pythonState.py -``` - -You should see an output similar to the following: - -```md -Starting Dapr with id Singerchecker-Player. HTTP Port: 59533. gRPC Port: 59534 -== DAPR == time="2021-01-06T22:18:14.1246721-08:00" level=info msg="starting Dapr Runtime -- version 0.11.3 -- commit a1a8e11" app_id=Singerchecker-Player scope=dapr.runtime type=log ver=0.11.3 -== DAPR == time="2021-01-06T22:18:14.1346254-08:00" level=info msg="standalone mode configured" app_id=Singerchecker-Player scope=dapr.runtime type=log ver=0.11.3 -== DAPR == time="2021-01-06T22:18:14.2747063-08:00" level=info msg="component loaded. name: statestore, type: state.redis" app_id=Singerchecker-Player scope=dapr.runtime type=log ver=0.11.3 -== DAPR == time="2021-01-06T22:18:14.2757062-08:00" level=info msg="API gRPC server is running on port 59534" app_id=Singerchecker-Player scope=dapr.runtime type=log ver=0.11.3 -== DAPR == time="2021-01-06T22:18:14.2767059-08:00" level=info msg="dapr initialized. Status: Running. Init Elapsed 142.0805ms" app_id=Singerchecker-Player scope=dapr.runtime type=log ver=0.11.3 - -Checking if Dapr sidecar is listening on GRPC port 59534 -Dapr sidecar is up and running. -Updating metadata for app command: python pythonState.py -You're up and running! Both Dapr and your app logs will appear here. - -== APP == State transactions have been completed -== APP == Got items: [b'value1', b''] -``` - -{{% /codetab %}} - -{{% codetab %}} - -Transactional state is supported by extending `TransactionalState` base object which hooks into your -object via setters and getters to provide a transaction. Before you created your own transactional object, -but now you'll ask the Dependency Injection framework to build one for you. - -Modify the `state-example.php` file again: - -```php -run(function(MyState $obj, \Psr\Log\LoggerInterface $logger, \Dapr\State\StateManager $stateManager) { - $obj->begin(); - $obj->key1 = 'hello world'; - $obj->key2 = 'value3'; - $obj->commit(); - $logger->alert('Transaction committed!'); - - // begin a new transaction which reloads from the store - $obj->begin(); - $logger->alert("Got value: {key1}, {key2}", ['key1' => $obj->key1, 'key2' => $obj->key2]); -}); -``` - -Run the application: - -```bash -dapr --app-id myapp run -- php state-example.php -``` - -Observe the following output: - -```md -✅ You're up and running! Both Dapr and your app logs will appear here. - -== APP == [2021-02-12T17:10:06.837110+01:00] APP.ALERT: Transaction committed! [] [] - -== APP == [2021-02-12T17:10:06.840857+01:00] APP.ALERT: Got value: hello world, value3 {"key1":"hello world","key2":"value3"} [] +Invoke-RestMethod -Method Post -ContentType 'application/json' -Body '{"keys":["order_1", "order_2"]}' -Uri 'http://localhost:3601/v1.0/state/statestore/bulk' ``` {{% /codetab %}} @@ -588,4 +750,4 @@ Observe the following output: - Read the full [State API reference]({{< ref state_api.md >}}) - Try one of the [Dapr SDKs]({{< ref sdks >}}) -- Build a [stateful service]({{< ref howto-stateful-service.md >}}) +- Build a [stateful service]({{< ref howto-stateful-service.md >}}) \ No newline at end of file From ad20a76b321feff8d43ef6cf26553a78c381330e Mon Sep 17 00:00:00 2001 From: Amulya Varote Date: Tue, 23 Nov 2021 03:09:03 -0800 Subject: [PATCH 03/30] Modified TTL page under state management --- .../state-management/state-store-ttl.md | 75 ++++++++----------- 1 file changed, 30 insertions(+), 45 deletions(-) diff --git a/daprdocs/content/en/developing-applications/building-blocks/state-management/state-store-ttl.md b/daprdocs/content/en/developing-applications/building-blocks/state-management/state-store-ttl.md index 14f0034f0..de57e9aa1 100644 --- a/daprdocs/content/en/developing-applications/building-blocks/state-management/state-store-ttl.md +++ b/daprdocs/content/en/developing-applications/building-blocks/state-management/state-store-ttl.md @@ -31,12 +31,38 @@ Please refer to the TTL column in the tables at [state store components]({{< ref State TTL can be set in the metadata as part of the state store set request: -{{< tabs "HTTP API (Bash)" "HTTP API (PowerShell)" "Python SDK" "PHP SDK">}} +{{< tabs Python "HTTP API (Bash)" "HTTP API (PowerShell)">}} + +{{% codetab %}} + +```python +#dependencies + +from dapr.clients import DaprClient + +#code + +DAPR_STORE_NAME = "statestore" + +with DaprClient() as client: + client.save_state(DAPR_STORE_NAME, "order_1", str(orderId), metadata=( + ('ttlInSeconds', '120') + )) + +``` + +Once saved run the following command to launch a Dapr sidecar and run the application: + +```bash +dapr run --app-id orderprocessing --app-port 6001 --dapr-http-port 3601 --dapr-grpc-port 60001 -- python3 OrderProcessingService.py +``` + +{{% /codetab %}} {{% codetab %}} ```bash -curl -X POST -H "Content-Type: application/json" -d '[{ "key": "key1", "value": "value1", "metadata": { "ttlInSeconds": "120" } }]' http://localhost:3500/v1.0/state/statestore +curl -X POST -H "Content-Type: application/json" -d '[{ "key": "order_1", "value": "250", "metadata": { "ttlInSeconds": "120" } }]' http://localhost:3601/v1.0/state/statestore ``` {{% /codetab %}} @@ -44,48 +70,7 @@ curl -X POST -H "Content-Type: application/json" -d '[{ "key": "key1", "value": {{% codetab %}} ```powershell -Invoke-RestMethod -Method Post -ContentType 'application/json' -Body '[{"key": "key1", "value": "value1", "metadata": {"ttlInSeconds": "120"}}]' -Uri 'http://localhost:3500/v1.0/state/statestore' -``` - -{{% /codetab %}} - -{{% codetab %}} - -```python -from dapr.clients import DaprClient - -with DaprClient() as d: - d.save_state( - store_name="statestore", - key="myFirstKey", - value="myFirstValue", - metadata=( - ('ttlInSeconds', '120') - ) - ) - print("State has been stored") - -``` - -{{% /codetab %}} - -{{% codetab %}} - -Save the following in `state-example.php`: - -```php -run(function(\Dapr\State\StateManager $stateManager, \Psr\Log\LoggerInterface $logger) { - $stateManager->save_state(store_name: 'statestore', item: new \Dapr\State\StateItem( - key: 'myFirstKey', - value: 'myFirstValue', - metadata: ['ttlInSeconds' => '120'] - )); - $logger->alert('State has been stored'); -}); +Invoke-RestMethod -Method Post -ContentType 'application/json' -Body '[{"key": "order_1", "value": "250", "metadata": {"ttlInSeconds": "120"}}]' -Uri 'http://localhost:3601/v1.0/state/statestore' ``` {{% /codetab %}} @@ -98,4 +83,4 @@ See [this guide]({{< ref state_api.md >}}) for a reference on the state API. - Learn [how to use key value pairs to persist a state]({{< ref howto-get-save-state.md >}}) - List of [state store components]({{< ref supported-state-stores >}}) -- Read the [API reference]({{< ref state_api.md >}}) +- Read the [API reference]({{< ref state_api.md >}}) \ No newline at end of file From d63571298946c1a149ef964bfb75fff960d9609b Mon Sep 17 00:00:00 2001 From: Amulya Varote Date: Tue, 23 Nov 2021 11:35:59 -0800 Subject: [PATCH 04/30] Added complete code snippets --- .../howto-invoke-discover-services.md | 171 +++-- .../state-management/howto-get-save-state.md | 592 +++++++++++++----- .../supported-pubsub/setup-nats-streaming.md | 2 +- 3 files changed, 566 insertions(+), 199 deletions(-) diff --git a/daprdocs/content/en/developing-applications/building-blocks/service-invocation/howto-invoke-discover-services.md b/daprdocs/content/en/developing-applications/building-blocks/service-invocation/howto-invoke-discover-services.md index 185d718ab..a902fe3de 100644 --- a/daprdocs/content/en/developing-applications/building-blocks/service-invocation/howto-invoke-discover-services.md +++ b/daprdocs/content/en/developing-applications/building-blocks/service-invocation/howto-invoke-discover-services.md @@ -185,17 +185,41 @@ Below are code examples that leverage Dapr SDKs for service invocation. ```csharp //dependencies - -using Dapr.Client; +using System; +using System.Collections.Generic; using System.Net.Http; +using System.Net.Http.Headers; +using System.Threading.Tasks; +using Dapr.Client; +using Microsoft.AspNetCore.Mvc; +using System.Threading; //code +namespace EventService +{ + class Program + { + static async Task Main(string[] args) + { + //Calling service multiple times with 5 seconds gap in between the calls + while(true) { + System.Threading.Thread.Sleep(5000); + Random random = new Random(); + int orderId = random.Next(1,1000); -CancellationTokenSource source = new CancellationTokenSource(); -CancellationToken cancellationToken = source.Token; -using var client = new DaprClientBuilder().Build(); -var result = client.CreateInvokeMethodRequest(HttpMethod.Get, "checkout", "checkout/" + orderId, cancellationToken); -await client.InvokeMethodAsync(result); + CancellationTokenSource source = new CancellationTokenSource(); + CancellationToken cancellationToken = source.Token; + //Using Dapr SDK to invoke a method + using var client = new DaprClientBuilder().Build(); + var result = client.CreateInvokeMethodRequest(HttpMethod.Get, "checkout", "checkout/" + orderId, cancellationToken); + await client.InvokeMethodAsync(result); + + Console.WriteLine("Order requested: " + orderId); + Console.WriteLine("Result: " + result); + } + } + } +} ``` {{% /codetab %}} @@ -205,21 +229,45 @@ await client.InvokeMethodAsync(result); ```java //dependencies - import io.dapr.client.DaprClient; import io.dapr.client.DaprClientBuilder; import io.dapr.client.domain.HttpExtension; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Random; +import java.util.concurrent.TimeUnit; //code +@SpringBootApplication +public class OrderProcessingServiceApplication { -DaprClient daprClient = new DaprClientBuilder().build(); -var result = daprClient.invokeMethod( - "checkout", - "checkout/" + orderId, - null, - HttpExtension.GET, - String.class -); + private static final Logger log = LoggerFactory.getLogger(OrderProcessingServiceApplication.class); + + public static void main(String[] args) throws InterruptedException{ + + //Calling service multiple times with 5 seconds gap in between the calls + while(true) { + TimeUnit.MILLISECONDS.sleep(5000); + Random random = new Random(); + int orderId = random.nextInt(1000-1) + 1; + + //Using Dapr SDK to invoke a method + DaprClient client = new DaprClientBuilder().build(); + var result = client.invokeMethod( + "checkout", + "checkout/" + orderId, + null, + HttpExtension.GET, + String.class + ); + + log.info("Order requested: " + orderId); + log.info("Result: " + result); + } + } +} ``` {{% /codetab %}} @@ -228,18 +276,31 @@ var result = daprClient.invokeMethod( ```python #dependencies - +import random +from time import sleep +import requests +import logging from dapr.clients import DaprClient #code +logging.basicConfig(level = logging.INFO) + +#Calling service multiple times with 5 seconds gap in between the calls +while True: + sleep(random.randrange(50, 5000) / 1000) + orderId = random.randint(1, 1000) -with DaprClient() as daprClient: - result = daprClient.invoke_method( - "checkout", - f"checkout/{orderId}", - data=b'', - http_verb="GET" - ) + #Using Dapr SDK to invoke a method + with DaprClient() as client: + result = client.invoke_method( + "checkout", + f"checkout/{orderId}", + data=b'', + http_verb="GET" + ) + logging.basicConfig(level = logging.INFO) + logging.info('Order requested: ' + str(orderId)) + logging.info('Result: ' + str(result)) ``` {{% /codetab %}} @@ -249,19 +310,37 @@ with DaprClient() as daprClient: //dependencies import ( - dapr "github.com/dapr/go-sdk/client" + "context" + "log" + "math/rand" + "time" + "strconv" + dapr "github.com/dapr/go-sdk/client" + ) //code +func main() { -client, err := dapr.NewClient() -if err != nil { - panic(err) + //Calling service multiple times with 5 seconds gap in between the calls + for i := 0; i < 10; i++ { + time.Sleep(5000) + orderId := rand.Intn(1000-1) + 1 + + //Using Dapr SDK to invoke a method + client, err := dapr.NewClient() + if err != nil { + panic(err) + } + defer client.Close() + ctx := context.Background() + result, err := client.InvokeMethod(ctx, "checkout", "checkout/" + strconv.Itoa(orderId), "get") + + log.Println("Order requested: " + strconv.Itoa(orderId)) + log.Println("Result: ") + log.Println(result) + } } -defer client.Close() -ctx := context.Background() - -result, err := client.InvokeMethod(ctx, "checkout", "checkout/" + strconv.Itoa(orderId), "get") ``` {{% /codetab %}} @@ -270,14 +349,32 @@ result, err := client.InvokeMethod(ctx, "checkout", "checkout/" + strconv.Itoa(o ```javascript //dependencies - import { DaprClient, HttpMethod, CommunicationProtocolEnum } from 'dapr-client'; -//code - const daprHost = "127.0.0.1"; -const client = new DaprClient(daprHost, process.env.DAPR_HTTP_PORT, CommunicationProtocolEnum.HTTP); -const result = await client.invoker.invoke('checkout' , "checkout/" + orderId , HttpMethod.GET); + +//code +var main = function() { + + //Calling service multiple times with 5 seconds gap in between the calls + for(var i=0;i<10;i++) { + sleep(5000); + var orderId = Math.floor(Math.random() * (1000 - 1) + 1); + + //Using Dapr SDK to invoke a method + const client = new DaprClient(daprHost, process.env.DAPR_HTTP_PORT, CommunicationProtocolEnum.HTTP); + const result = await client.invoker.invoke('checkout' , "checkout/" + orderId , HttpMethod.GET); + + console.log("Order requested: " + orderId); + console.log("Result: " + result); + } +} + +function sleep(ms) { + return new Promise(resolve => setTimeout(resolve, ms)); +} + +main(); ``` {{% /codetab %}} diff --git a/daprdocs/content/en/developing-applications/building-blocks/state-management/howto-get-save-state.md b/daprdocs/content/en/developing-applications/building-blocks/state-management/howto-get-save-state.md index e3a678037..e096b8c18 100644 --- a/daprdocs/content/en/developing-applications/building-blocks/state-management/howto-get-save-state.md +++ b/daprdocs/content/en/developing-applications/building-blocks/state-management/howto-get-save-state.md @@ -66,7 +66,7 @@ See the instructions [here]({{< ref "setup-state-store" >}}) on how to setup dif ## Step 2: Save and retrieve a single state -The following example shows how to a single key/value pair using the Dapr state building block. +The following example shows how to save and retrieve a single key/value pair using the Dapr state building block. {{% alert title="Note" color="warning" %}} It is important to set an app-id, as the state keys are prefixed with this value. If you don't set it one is generated for you at runtime, and the next time you run the command a new one will be generated and you will no longer be able to access previously saved state. @@ -79,18 +79,43 @@ Below are code examples that leverage Dapr SDKs for saving and retrieving a sing {{% codetab %}} ```csharp -//dependencies +//dependencies +using System; +using System.Collections.Generic; +using System.Net.Http; +using System.Net.Http.Headers; +using System.Threading.Tasks; using Dapr.Client; +using Microsoft.AspNetCore.Mvc; +using System.Threading; +using System.Text.Json; //code +namespace EventService +{ + class Program + { + static async Task Main(string[] args) + { + string DAPR_STORE_NAME = "statestore"; -string DAPR_STORE_NAME = "statestore"; + //Calling service multiple times with 5 seconds gap in between the calls + while(true) { + System.Threading.Thread.Sleep(5000); + Random random = new Random(); + int orderId = random.Next(1,1000); -using var client = new DaprClientBuilder().Build(); -await client.SaveStateAsync(DAPR_STORE_NAME, "order_1", orderId.ToString()); -var result = await client.GetStateAsync(DAPR_STORE_NAME, orderId.ToString()); -Console.WriteLine("Result after get: " + result); + //Using Dapr SDK to save and get state + using var client = new DaprClientBuilder().Build(); + await client.SaveStateAsync(DAPR_STORE_NAME, "order_1", orderId.ToString()); + await client.SaveStateAsync(DAPR_STORE_NAME, "order_2", orderId.ToString()); + var result = await client.GetStateAsync(DAPR_STORE_NAME, orderId.ToString()); + Console.WriteLine("Result after get: " + result); + } + } + } +} ``` @@ -103,23 +128,46 @@ dapr run --app-id orderprocessing --app-port 6001 --dapr-http-port 3601 --dapr-g {{% /codetab %}} - {{% codetab %}} ```java -//dependencies +//dependencies import io.dapr.client.DaprClient; import io.dapr.client.DaprClientBuilder; +import io.dapr.client.domain.State; +import io.dapr.client.domain.TransactionalStateOperation; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import reactor.core.publisher.Mono; +import java.util.Random; +import java.util.concurrent.TimeUnit; //code +@SpringBootApplication +public class OrderProcessingServiceApplication { -private static final String STATE_STORE_NAME = "statestore"; + private static final Logger log = LoggerFactory.getLogger(OrderProcessingServiceApplication.class); -DaprClient client = new DaprClientBuilder().build(); -client.saveState(STATE_STORE_NAME, "order_1", Integer.toString(orderId)).block(); -Mono> result = client.getState(STATE_STORE_NAME, "order_1", String.class); -log.info("Result after get" + result); + public static void main(String[] args) throws InterruptedException{ + String STATE_STORE_NAME = "statestore"; + + //Calling service multiple times with 5 seconds gap in between the calls + while(true) { + TimeUnit.MILLISECONDS.sleep(5000); + Random random = new Random(); + int orderId = random.nextInt(1000-1) + 1; + + //Using Dapr SDK to save and get state + DaprClient client = new DaprClientBuilder().build(); + client.saveState(STATE_STORE_NAME, "order_1", Integer.toString(orderId)).block(); + client.saveState(STATE_STORE_NAME, "order_2", Integer.toString(orderId)).block(); + Mono> result = client.getState(STATE_STORE_NAME, "order_1", String.class); + log.info("Result after get" + result); + } + } +} ``` @@ -135,15 +183,28 @@ dapr run --app-id orderprocessing --app-port 6001 --dapr-http-port 3601 --dapr-g {{% codetab %}} ```python -#dependencies +#dependencies +import random +from time import sleep +import requests +import logging from dapr.clients import DaprClient +from dapr.clients.grpc._state import StateItem +from dapr.clients.grpc._request import TransactionalStateOperation, TransactionOperationType #code - +logging.basicConfig(level = logging.INFO) + DAPR_STORE_NAME = "statestore" -with DaprClient() as client: +#Calling service multiple times with 5 seconds gap in between the calls +while True: + sleep(random.randrange(50, 5000) / 1000) + orderId = random.randint(1, 1000) + + #Using Dapr SDK to save and get state + with DaprClient() as client: client.save_state(DAPR_STORE_NAME, "order_1", str(orderId)) result = client.get_state(DAPR_STORE_NAME, "order_1") logging.info('Result after get: ' + str(result)) @@ -162,35 +223,49 @@ dapr run --app-id orderprocessing --app-port 6001 --dapr-http-port 3601 --dapr-g {{% codetab %}} ```go -//dependencies +//dependencies import ( - dapr "github.com/dapr/go-sdk/client" + "context" + "log" + "math/rand" + "time" + "strconv" + dapr "github.com/dapr/go-sdk/client" + ) //code +func main() { -client, err := dapr.NewClient() -STATE_STORE_NAME := "statestore" + STATE_STORE_NAME := "statestore" -if err != nil { - panic(err) + //Calling service multiple times with 5 seconds gap in between the calls + for i := 0; i < 10; i++ { + time.Sleep(5000) + orderId := rand.Intn(1000-1) + 1 + + //Using Dapr SDK to save and get state + client, err := dapr.NewClient() + if err != nil { + panic(err) + } + defer client.Close() + ctx := context.Background() + + if err := client.SaveState(ctx, STATE_STORE_NAME, "order_1", []byte(strconv.Itoa(orderId))); err != nil { + panic(err) + } + + result, err := client.GetState(ctx, STATE_STORE_NAME, "order_1") + if err != nil { + panic(err) + } + + log.Println("Result after get: ") + log.Println(result) + } } -defer client.Close() -ctx := context.Background() - -if err := client.SaveState(ctx, store, "order_1", []byte(strconv.Itoa(orderId))); err != nil { - panic(err) -} - -result, err := client.GetState(ctx, store, "order_2") -if err != nil { - panic(err) -} - -log.Println("Result after get: ") -log.Println(result) - ``` @@ -206,24 +281,43 @@ dapr run --app-id orderprocessing --app-port 6001 --dapr-http-port 3601 --dapr-g {{% codetab %}} ```javascript -//dependencies +//dependencies import { DaprClient, HttpMethod, CommunicationProtocolEnum } from 'dapr-client'; //code - -const STATE_STORE_NAME = "statestore"; - const daprHost = "127.0.0.1"; -const client = new DaprClient(daprHost, process.env.DAPR_HTTP_PORT, CommunicationProtocolEnum.HTTP); -await client.state.save(STATE_STORE_NAME, [ -{ - key: "order_1", - value: orderId.toString() -}]); -var result = await client.state.get(STATE_STORE_NAME, "order_1"); -console.log("Result after get: " + result); +var main = function() { + const STATE_STORE_NAME = "statestore"; + + //Calling service multiple times with 5 seconds gap in between the calls + for(var i=0;i<10;i++) { + sleep(5000); + var orderId = Math.floor(Math.random() * (1000 - 1) + 1); + + //Using Dapr SDK to save and get state + const client = new DaprClient(daprHost, process.env.DAPR_HTTP_PORT, CommunicationProtocolEnum.HTTP); + await client.state.save(STATE_STORE_NAME, [ + { + key: "order_1", + value: orderId.toString() + }, + { + key: "order_2", + value: orderId.toString() + } + ]); + var result = await client.state.get(STATE_STORE_NAME, "order_1"); + console.log("Result after get: " + result); + } +} + +function sleep(ms) { + return new Promise(resolve => setTimeout(resolve, ms)); +} + +main(); ``` @@ -290,15 +384,32 @@ Below are code examples that leverage Dapr SDKs for deleting the state. {{% codetab %}} ```csharp -//dependencies +//dependencies +using System; +using System.Collections.Generic; +using System.Net.Http; +using System.Net.Http.Headers; +using System.Threading.Tasks; using Dapr.Client; +using Microsoft.AspNetCore.Mvc; +using System.Threading; +using System.Text.Json; //code - -string DAPR_STORE_NAME = "statestore"; - -await client.DeleteStateAsync(DAPR_STORE_NAME, "order_1", cancellationToken: cancellationToken); +namespace EventService +{ + class Program + { + static async Task Main(string[] args) + { + string DAPR_STORE_NAME = "statestore"; + //Using Dapr SDK to delete the state + using var client = new DaprClientBuilder().Build(); + await client.DeleteStateAsync(DAPR_STORE_NAME, "order_1", cancellationToken: cancellationToken); + } + } +} ``` @@ -314,18 +425,33 @@ dapr run --app-id orderprocessing --app-port 6001 --dapr-http-port 3601 --dapr-g {{% codetab %}} ```java -//dependencies +//dependencies import io.dapr.client.DaprClient; import io.dapr.client.DaprClientBuilder; +import io.dapr.client.domain.State; +import io.dapr.client.domain.TransactionalStateOperation; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import java.util.Random; +import java.util.concurrent.TimeUnit; //code +@SpringBootApplication +public class OrderProcessingServiceApplication { -private static final String STATE_STORE_NAME = "statestore"; + private static final Logger log = LoggerFactory.getLogger(OrderProcessingServiceApplication.class); -DaprClient client = new DaprClientBuilder().build(); -String storedEtag = client.getState(STATE_STORE_NAME, "order_1", String.class).block().getEtag(); -client.deleteState(STATE_STORE_NAME, "order_1", storedEtag, null).block(); + public static void main(String[] args) throws InterruptedException{ + String STATE_STORE_NAME = "statestore"; + + //Using Dapr SDK to delete the state + DaprClient client = new DaprClientBuilder().build(); + String storedEtag = client.getState(STATE_STORE_NAME, "order_1", String.class).block().getEtag(); + client.deleteState(STATE_STORE_NAME, "order_1", storedEtag, null).block(); + } +} ``` @@ -341,16 +467,24 @@ dapr run --app-id orderprocessing --app-port 6001 --dapr-http-port 3601 --dapr-g {{% codetab %}} ```python -#dependencies +#dependencies +import random +from time import sleep +import requests +import logging from dapr.clients import DaprClient +from dapr.clients.grpc._state import StateItem +from dapr.clients.grpc._request import TransactionalStateOperation, TransactionOperationType #code - +logging.basicConfig(level = logging.INFO) + DAPR_STORE_NAME = "statestore" +#Using Dapr SDK to delete the state with DaprClient() as client: - client.delete_state(store_name=DAPR_STORE_NAME, key="order_1") + client.delete_state(store_name=DAPR_STORE_NAME, key="order_1") ``` @@ -366,25 +500,30 @@ dapr run --app-id orderprocessing --app-port 6001 --dapr-http-port 3601 --dapr-g {{% codetab %}} ```go -//dependencies +//dependencies import ( - dapr "github.com/dapr/go-sdk/client" + "context" + dapr "github.com/dapr/go-sdk/client" + ) //code +func main() { -client, err := dapr.NewClient() -STATE_STORE_NAME := "statestore" + STATE_STORE_NAME := "statestore" -if err != nil { - panic(err) -} -defer client.Close() -ctx := context.Background() + //Using Dapr SDK to delete the state + client, err := dapr.NewClient() + if err != nil { + panic(err) + } + defer client.Close() + ctx := context.Background() -if err := client.DeleteState(ctx, store, "order_1"); err != nil { - panic(err) + if err := client.DeleteState(ctx, STATE_STORE_NAME, "order_1"); err != nil { + panic(err) + } } ``` @@ -401,17 +540,26 @@ dapr run --app-id orderprocessing --app-port 6001 --dapr-http-port 3601 --dapr-g {{% codetab %}} ```javascript -//dependencies +//dependencies import { DaprClient, HttpMethod, CommunicationProtocolEnum } from 'dapr-client'; //code +const daprHost = "127.0.0.1"; -const STATE_STORE_NAME = "statestore"; +var main = function() { + const STATE_STORE_NAME = "statestore"; -const client = new DaprClient(daprHost, process.env.DAPR_HTTP_PORT, CommunicationProtocolEnum.HTTP); -await client.state.delete(STATE_STORE_NAME, "order_1"); + //Using Dapr SDK to save and get state + const client = new DaprClient(daprHost, process.env.DAPR_HTTP_PORT, CommunicationProtocolEnum.HTTP); + await client.state.delete(STATE_STORE_NAME, "order_1"); +} +function sleep(ms) { + return new Promise(resolve => setTimeout(resolve, ms)); +} + +main(); ``` @@ -450,22 +598,41 @@ Below are code examples that leverage Dapr SDKs for saving and retrieving multip {{% codetab %}} ```java -//dependencies +//dependencies import io.dapr.client.DaprClient; import io.dapr.client.DaprClientBuilder; -import reactor.core.publisher.Mono; import io.dapr.client.domain.State; -import java.util.List; +import io.dapr.client.domain.TransactionalStateOperation; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import reactor.core.publisher.Mono; +import java.util.Random; +import java.util.concurrent.TimeUnit; //code +@SpringBootApplication +public class OrderProcessingServiceApplication { -private static final String STATE_STORE_NAME = "statestore"; + private static final Logger log = LoggerFactory.getLogger(OrderProcessingServiceApplication.class); -DaprClient client = new DaprClientBuilder().build(); -Mono>> resultBulk = client.getBulkState(STATE_STORE_NAME, - Arrays.asList("order_1", "order_2"), String.class); -log.info("Result after get bulk" + resultBulk); + public static void main(String[] args) throws InterruptedException{ + String STATE_STORE_NAME = "statestore"; + + //Calling service multiple times with 5 seconds gap in between the calls + while(true) { + TimeUnit.MILLISECONDS.sleep(5000); + Random random = new Random(); + int orderId = random.nextInt(1000-1) + 1; + + //Using Dapr SDK to retrieve multiple states + DaprClient client = new DaprClientBuilder().build(); + Mono>> resultBulk = client.getBulkState(STATE_STORE_NAME, + Arrays.asList("order_1", "order_2"), String.class); + } + } +} ``` @@ -481,19 +648,31 @@ dapr run --app-id orderprocessing --app-port 6001 --dapr-http-port 3601 --dapr-g {{% codetab %}} ```python -#dependencies +#dependencies +import random +from time import sleep +import requests +import logging from dapr.clients import DaprClient from dapr.clients.grpc._state import StateItem +from dapr.clients.grpc._request import TransactionalStateOperation, TransactionOperationType #code - +logging.basicConfig(level = logging.INFO) + DAPR_STORE_NAME = "statestore" -with DaprClient() as client: - client.save_bulk_state(store_name=DAPR_STORE_NAME, states=[StateItem(key="order_2", value=str(orderId))]) - result = client.get_bulk_state(store_name=DAPR_STORE_NAME, keys=["order_1", "order_2"], states_metadata={"metakey": "metavalue"}).items - logging.info('Result after get bulk: ' + str(result)) +#Calling service multiple times with 5 seconds gap in between the calls +while True: + sleep(random.randrange(50, 5000) / 1000) + orderId = random.randint(1, 1000) + + #Using Dapr SDK to save and retrieve multiple states + with DaprClient() as client: + client.save_bulk_state(store_name=DAPR_STORE_NAME, states=[StateItem(key="order_2", value=str(orderId))]) + result = client.get_bulk_state(store_name=DAPR_STORE_NAME, keys=["order_1", "order_2"], states_metadata={"metakey": "metavalue"}).items + logging.info('Result after get bulk: ' + str(result)) ``` @@ -510,26 +689,43 @@ dapr run --app-id orderprocessing --app-port 6001 --dapr-http-port 3601 --dapr-g {{% codetab %}} ```javascript -//dependencies +//dependencies import { DaprClient, HttpMethod, CommunicationProtocolEnum } from 'dapr-client'; //code +const daprHost = "127.0.0.1"; -const client = new DaprClient(daprHost, process.env.DAPR_HTTP_PORT, CommunicationProtocolEnum.HTTP); -const STATE_STORE_NAME = "statestore"; -await client.state.save(STATE_STORE_NAME, [ - { - key: "order_1", - value: orderId.toString() - }, - { - key: "order_2", - value: orderId.toString() - } -]); -result = await client.state.getBulk(STATE_STORE_NAME, ["order_1", "order_2"]); -console.log("Result after get bulk: " + result); +var main = function() { + const STATE_STORE_NAME = "statestore"; + + //Calling service multiple times with 5 seconds gap in between the calls + for(var i=0;i<10;i++) { + sleep(5000); + var orderId = Math.floor(Math.random() * (1000 - 1) + 1); + + //Using Dapr SDK to save and retrieve multiple states + const client = new DaprClient(daprHost, process.env.DAPR_HTTP_PORT, CommunicationProtocolEnum.HTTP); + await client.state.save(STATE_STORE_NAME, [ + { + key: "order_1", + value: orderId.toString() + }, + { + key: "order_2", + value: orderId.toString() + } + ]); + result = await client.state.getBulk(STATE_STORE_NAME, ["order_1", "order_2"]); + console.log("Result after get bulk: " + result); + } +} + +function sleep(ms) { + return new Promise(resolve => setTimeout(resolve, ms)); +} + +main(); ``` @@ -581,24 +777,46 @@ Below are code examples that leverage Dapr SDKs for performing state transaction {{% codetab %}} ```csharp -//dependencies +//dependencies +using System; +using System.Collections.Generic; +using System.Net.Http; +using System.Net.Http.Headers; +using System.Threading.Tasks; using Dapr.Client; +using Microsoft.AspNetCore.Mvc; +using System.Threading; +using System.Text.Json; //code - -string DAPR_STORE_NAME = "statestore"; -using var client = new DaprClientBuilder().Build(); -var requests = new List() +namespace EventService { - new StateTransactionRequest("order_3", JsonSerializer.SerializeToUtf8Bytes(orderId.ToString()), StateOperationType.Upsert), - new StateTransactionRequest("order_2", null, StateOperationType.Delete) -}; + class Program + { + static async Task Main(string[] args) + { + string DAPR_STORE_NAME = "statestore"; + //Calling service multiple times with 5 seconds gap in between the calls + while(true) { + System.Threading.Thread.Sleep(5000); + Random random = new Random(); + int orderId = random.Next(1,1000); -CancellationTokenSource source = new CancellationTokenSource(); -CancellationToken cancellationToken = source.Token; - -await client.ExecuteStateTransactionAsync(DAPR_STORE_NAME, requests, cancellationToken: cancellationToken); + //Using Dapr SDK to perform the state transactions + using var client = new DaprClientBuilder().Build(); + var requests = new List() + { + new StateTransactionRequest("order_3", JsonSerializer.SerializeToUtf8Bytes(orderId.ToString()), StateOperationType.Upsert), + new StateTransactionRequest("order_2", null, StateOperationType.Delete) + }; + CancellationTokenSource source = new CancellationTokenSource(); + CancellationToken cancellationToken = source.Token; + await client.ExecuteStateTransactionAsync(DAPR_STORE_NAME, requests, cancellationToken: cancellationToken); + } + } + } +} ``` @@ -614,24 +832,48 @@ dapr run --app-id orderprocessing --app-port 6001 --dapr-http-port 3601 --dapr-g {{% codetab %}} ```java -//dependencies +//dependencies import io.dapr.client.DaprClient; import io.dapr.client.DaprClientBuilder; import io.dapr.client.domain.State; import io.dapr.client.domain.TransactionalStateOperation; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import reactor.core.publisher.Mono; +import java.util.Random; +import java.util.concurrent.TimeUnit; //code +@SpringBootApplication +public class OrderProcessingServiceApplication { -private static final String STATE_STORE_NAME = "statestore"; + private static final Logger log = LoggerFactory.getLogger(OrderProcessingServiceApplication.class); -DaprClient client = new DaprClientBuilder().build(); -List> operationList = new ArrayList<>(); -operationList.add(new TransactionalStateOperation<>(TransactionalStateOperation.OperationType.UPSERT, - new State<>("order_3", Integer.toString(orderId), ""))); -operationList.add(new TransactionalStateOperation<>(TransactionalStateOperation.OperationType.DELETE, - new State<>("order_2"))); -client.executeStateTransaction(STATE_STORE_NAME, operationList).block(); + public static void main(String[] args) throws InterruptedException{ + String STATE_STORE_NAME = "statestore"; + + //Calling service multiple times with 5 seconds gap in between the calls + while(true) { + TimeUnit.MILLISECONDS.sleep(5000); + Random random = new Random(); + int orderId = random.nextInt(1000-1) + 1; + + //Using Dapr SDK to perform the state transactions + DaprClient client = new DaprClientBuilder().build(); + List> operationList = new ArrayList<>(); + operationList.add(new TransactionalStateOperation<>(TransactionalStateOperation.OperationType.UPSERT, + new State<>("order_3", Integer.toString(orderId), ""))); + operationList.add(new TransactionalStateOperation<>(TransactionalStateOperation.OperationType.DELETE, + new State<>("order_2"))); + client.executeStateTransaction(STATE_STORE_NAME, operationList).block(); + } + } +} ``` @@ -647,28 +889,40 @@ dapr run --app-id orderprocessing --app-port 6001 --dapr-http-port 3601 --dapr-g {{% codetab %}} ```python -#dependencies +#dependencies +import random +from time import sleep +import requests +import logging from dapr.clients import DaprClient from dapr.clients.grpc._state import StateItem from dapr.clients.grpc._request import TransactionalStateOperation, TransactionOperationType #code - +logging.basicConfig(level = logging.INFO) + DAPR_STORE_NAME = "statestore" -with DaprClient() as client: - client.execute_state_transaction(store_name=DAPR_STORE_NAME, operations=[ - TransactionalStateOperation( - operation_type=TransactionOperationType.upsert, - key="order_3", - data=str(orderId)), - TransactionalStateOperation(key="order_3", data=str(orderId)), - TransactionalStateOperation( - operation_type=TransactionOperationType.delete, - key="order_2", - data=str(orderId)), - TransactionalStateOperation(key="order_2", data=str(orderId)) - ]) + +#Calling service multiple times with 5 seconds gap in between the calls +while True: + sleep(random.randrange(50, 5000) / 1000) + orderId = random.randint(1, 1000) + + #Using Dapr SDK to perform the state transactions + with DaprClient() as client: + client.execute_state_transaction(store_name=DAPR_STORE_NAME, operations=[ + TransactionalStateOperation( + operation_type=TransactionOperationType.upsert, + key="order_3", + data=str(orderId)), + TransactionalStateOperation(key="order_3", data=str(orderId)), + TransactionalStateOperation( + operation_type=TransactionOperationType.delete, + key="order_2", + data=str(orderId)), + TransactionalStateOperation(key="order_2", data=str(orderId)) + ]) ``` @@ -684,30 +938,46 @@ dapr run --app-id orderprocessing --app-port 6001 --dapr-http-port 3601 --dapr-g {{% codetab %}} ```javascript -//dependencies +//dependencies import { DaprClient, HttpMethod, CommunicationProtocolEnum } from 'dapr-client'; - //code +const daprHost = "127.0.0.1"; -const STATE_STORE_NAME = "statestore"; -const client = new DaprClient(daprHost, process.env.DAPR_HTTP_PORT, CommunicationProtocolEnum.HTTP); -await client.state.transaction(STATE_STORE_NAME, [ - { - operation: "upsert", - request: { - key: "order_3", - value: orderId.toString() +var main = function() { + const STATE_STORE_NAME = "statestore"; + + //Calling service multiple times with 5 seconds gap in between the calls + for(var i=0;i<10;i++) { + sleep(5000); + var orderId = Math.floor(Math.random() * (1000 - 1) + 1); + + //Using Dapr SDK to save and retrieve multiple states + const client = new DaprClient(daprHost, process.env.DAPR_HTTP_PORT, CommunicationProtocolEnum.HTTP); + await client.state.transaction(STATE_STORE_NAME, [ + { + operation: "upsert", + request: { + key: "order_3", + value: orderId.toString() + } + }, + { + operation: "delete", + request: { + key: "order_2" + } + } + ]); } - }, - { - operation: "delete", - request: { - key: "order_2" - } - } -]); +} + +function sleep(ms) { + return new Promise(resolve => setTimeout(resolve, ms)); +} + +main(); ``` diff --git a/daprdocs/content/en/reference/components-reference/supported-pubsub/setup-nats-streaming.md b/daprdocs/content/en/reference/components-reference/supported-pubsub/setup-nats-streaming.md index 38c281b4f..e9f7f4079 100644 --- a/daprdocs/content/en/reference/components-reference/supported-pubsub/setup-nats-streaming.md +++ b/daprdocs/content/en/reference/components-reference/supported-pubsub/setup-nats-streaming.md @@ -92,7 +92,7 @@ You can then interact with the server using the client port: `localhost:4222`. {{% /codetab %}} {{% codetab %}} -Install NATS on Kubernetes by using the [kubectl](https://docs.nats.io/nats-on-kubernetes/minimal-setup): +Install NATS on Kubernetes by using the [kubectl](https://docs.nats.io/running-a-nats-service/introduction/running/nats-kubernetes/minimal-setup#minimal-nats-setup): ```bash # Single server NATS From d4acb556afca2ae7ee00aed666557917625db5f6 Mon Sep 17 00:00:00 2001 From: Bernd Verst <4535280+berndverst@users.noreply.github.com> Date: Tue, 23 Nov 2021 20:26:45 -0800 Subject: [PATCH 05/30] Fix incorrect warning log-level --- .../en/operations/troubleshooting/logs-troubleshooting.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/daprdocs/content/en/operations/troubleshooting/logs-troubleshooting.md b/daprdocs/content/en/operations/troubleshooting/logs-troubleshooting.md index 242b271ac..b212bf3e7 100644 --- a/daprdocs/content/en/operations/troubleshooting/logs-troubleshooting.md +++ b/daprdocs/content/en/operations/troubleshooting/logs-troubleshooting.md @@ -14,7 +14,7 @@ Logs have different, configurable verbosity levels. The levels outlined below are the same for both system components and the Dapr sidecar process/container: 1. error -2. warning +2. warn 3. info 4. debug @@ -34,13 +34,13 @@ This will start the Dapr runtime binary with a log level of `error` and the Dapr To set the log level when running your app with the Dapr CLI, pass the `log-level` param: ```bash -dapr run --log-level warning node myapp.js +dapr run --log-level warn node myapp.js ``` As outlined above, every Dapr binary takes a `--log-level` argument. For example, to launch the placement service with a log level of warning: ```bash -./placement --log-level warning +./placement --log-level warn ``` ### Viewing Logs on Standalone Mode @@ -62,7 +62,7 @@ dapr run node myapp.js == DAPR == time="2019-09-05T12:26:43-07:00" level=info msg="loaded component messagebus (pubsub.redis)" == DAPR == 2019/09/05 12:26:43 redis: connecting to localhost:6379 == DAPR == 2019/09/05 12:26:43 redis: connected to localhost:6379 (localAddr: [::1]:56734, remAddr: [::1]:6379) -== DAPR == time="2019-09-05T12:26:43-07:00" level=warning msg="failed to init input bindings: app channel not initialized" +== DAPR == time="2019-09-05T12:26:43-07:00" level=warn msg="failed to init input bindings: app channel not initialized" == DAPR == time="2019-09-05T12:26:43-07:00" level=info msg="actor runtime started. actor idle timeout: 1h0m0s. actor scan interval: 30s" == DAPR == time="2019-09-05T12:26:43-07:00" level=info msg="actors: starting connection attempt to placement service at localhost:50005" == DAPR == time="2019-09-05T12:26:43-07:00" level=info msg="http server is running on port 56730" From 5c50a4eec3462a02a0a50c773be50edff9508391 Mon Sep 17 00:00:00 2001 From: Bernd Verst <4535280+berndverst@users.noreply.github.com> Date: Tue, 23 Nov 2021 20:28:30 -0800 Subject: [PATCH 06/30] Correct the default component init timeout --- daprdocs/content/en/operations/components/component-schema.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/daprdocs/content/en/operations/components/component-schema.md b/daprdocs/content/en/operations/components/component-schema.md index a7fc3f718..09fd461ea 100644 --- a/daprdocs/content/en/operations/components/component-schema.md +++ b/daprdocs/content/en/operations/components/component-schema.md @@ -38,7 +38,7 @@ spec: | **spec** | - | **Detailed information on the component resource** | spec.type | Y | The type of the component | `state.redis` | spec.version | Y | The version of the component | `v1` -| spec.initTimeout | N | The timeout duration for the initialization of the component. Default is 30s | `5m`, `1h`, `20s` +| spec.initTimeout | N | The timeout duration for the initialization of the component. Default is 5s | `5m`, `1h`, `20s` | spec.ignoreErrors | N | Tells the Dapr sidecar to continue initialization if the component fails to load. Default is false | `false` | **spec.metadata** | - | **A key/value pair of component specific configuration. See your component definition for fields**| From b1e0921761eac297dea07bceb88b818a156a60bb Mon Sep 17 00:00:00 2001 From: Amulya Varote Date: Wed, 24 Nov 2021 07:14:06 -0800 Subject: [PATCH 07/30] Modification based on the review comment - 1 --- .../building-blocks/state-management/howto-get-save-state.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/daprdocs/content/en/developing-applications/building-blocks/state-management/howto-get-save-state.md b/daprdocs/content/en/developing-applications/building-blocks/state-management/howto-get-save-state.md index e096b8c18..ab784b559 100644 --- a/daprdocs/content/en/developing-applications/building-blocks/state-management/howto-get-save-state.md +++ b/daprdocs/content/en/developing-applications/building-blocks/state-management/howto-get-save-state.md @@ -21,7 +21,7 @@ In this guide we'll start of with the basics: Using the key/value state API to a ## Example: -The below code examples loosely describe an application that processes orders. In the examples, there is one service - an order processing service. This service has Dapr sidecar and the order processing service uses Dapr to store state in redis state store. +The below code examples loosely describe an application that processes orders. In the examples, there is an order processing service which has a Dapr sidecar. The order processing service uses Dapr to store state in a Redis state store. Diagram showing state management of example service From 10853723253f65fa87e44ef0ecf21d7ddcf3f27e Mon Sep 17 00:00:00 2001 From: Amulya Varote Date: Wed, 24 Nov 2021 07:21:07 -0800 Subject: [PATCH 08/30] Fixed external validation checks --- .../components-reference/supported-pubsub/setup-jetstream.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/daprdocs/content/en/reference/components-reference/supported-pubsub/setup-jetstream.md b/daprdocs/content/en/reference/components-reference/supported-pubsub/setup-jetstream.md index 61e4711cb..791a2f02b 100644 --- a/daprdocs/content/en/reference/components-reference/supported-pubsub/setup-jetstream.md +++ b/daprdocs/content/en/reference/components-reference/supported-pubsub/setup-jetstream.md @@ -86,7 +86,7 @@ with NATS, find the service with: `kubectl get svc my-nats`. - [Basic schema for a Dapr component]({{< ref component-schema >}}) - Read [this guide]({{< ref "howto-publish-subscribe.md#step-2-publish-a-topic" >}}) for instructions on configuring pub/sub components - [Pub/Sub building block]({{< ref pubsub >}}) -- [JetStream Documentation](https://docs.nats.io/jetstream/jetstream) +- [JetStream Documentation](https://docs.nats.io/nats-concepts/jetstream) - [NATS CLI](https://github.com/nats-io/natscli) From fa5ab82209d83c9730d7f8386af981eb11cf70c4 Mon Sep 17 00:00:00 2001 From: Majid Ramezanpour Date: Wed, 24 Nov 2021 21:05:01 +0200 Subject: [PATCH 09/30] Update faq.md to include Go SDK actor availability From version v1.5.0, virtual actors are now available in the Dapr Go SDK. See go-sdk/21 for details --- daprdocs/content/en/concepts/faq.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/daprdocs/content/en/concepts/faq.md b/daprdocs/content/en/concepts/faq.md index fbe8a3219..e63045df8 100644 --- a/daprdocs/content/en/concepts/faq.md +++ b/daprdocs/content/en/concepts/faq.md @@ -25,7 +25,7 @@ Virtual actor capabilities are one of the building blocks that Dapr provides in Creating a new actor follows a local call like `http://localhost:3500/v1.0/actors///…`. For example, `http://localhost:3500/v1.0/actors/myactor/50/method/getData` calls the `getData` method on the newly created `myactor` with id `50`. -The Dapr runtime SDKs have language-specific actor frameworks. For example, the .NET SDK has C# actors. The goal is for all the Dapr language SDKs to have an actor framework. Currently .NET, Java and Python SDK have actor frameworks. +The Dapr runtime SDKs have language-specific actor frameworks. For example, the .NET SDK has C# actors. The goal is for all the Dapr language SDKs to have an actor framework. Currently .NET, Java, Go and Python SDK have actor frameworks. ## Developer language SDKs and frameworks From 3f307294574d07dee3af4e52342d049c089a4806 Mon Sep 17 00:00:00 2001 From: Massimo Crippa Date: Fri, 26 Nov 2021 16:43:45 +0100 Subject: [PATCH 10/30] fix: small typo replace semicolons with colons there are a couple of semicolons that should be colons --- .../en/operations/configuration/configuration-overview.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/daprdocs/content/en/operations/configuration/configuration-overview.md b/daprdocs/content/en/operations/configuration/configuration-overview.md index a9b941a30..55f5742a1 100644 --- a/daprdocs/content/en/operations/configuration/configuration-overview.md +++ b/daprdocs/content/en/operations/configuration/configuration-overview.md @@ -16,7 +16,7 @@ In self hosted mode the Dapr configuration is a configuration file, for example A Dapr sidecar can also apply a configuration by using a ```--config``` flag to the file path with ```dapr run``` CLI command. #### Kubernetes sidecar -In Kubernetes mode the Dapr configuration is a Configuration CRD, that is applied to the cluster. For example; +In Kubernetes mode the Dapr configuration is a Configuration CRD, that is applied to the cluster. For example: ```bash kubectl apply -f myappconfig.yaml @@ -41,7 +41,7 @@ Note: There are more [Kubernetes annotations]({{< ref "arguments-annotations-ove ### Sidecar configuration settings -The following configuration settings can be applied to Dapr application sidecars; +The following configuration settings can be applied to Dapr application sidecars: - [Tracing](#tracing) - [Metrics](#metrics) - [Middleware](#middleware) From bdba7a680063296481cee81d9babde0eeb3d0e7c Mon Sep 17 00:00:00 2001 From: Amulya Varote Date: Mon, 29 Nov 2021 12:39:52 -0800 Subject: [PATCH 11/30] Changes based on review comments - 2 --- .../howto-invoke-discover-services.md | 159 ++---- .../state-management/howto-get-save-state.md | 465 ++++++------------ .../state-management/state-store-ttl.md | 2 +- 3 files changed, 196 insertions(+), 430 deletions(-) diff --git a/daprdocs/content/en/developing-applications/building-blocks/service-invocation/howto-invoke-discover-services.md b/daprdocs/content/en/developing-applications/building-blocks/service-invocation/howto-invoke-discover-services.md index a902fe3de..d7ec89069 100644 --- a/daprdocs/content/en/developing-applications/building-blocks/service-invocation/howto-invoke-discover-services.md +++ b/daprdocs/content/en/developing-applications/building-blocks/service-invocation/howto-invoke-discover-services.md @@ -185,14 +185,7 @@ Below are code examples that leverage Dapr SDKs for service invocation. ```csharp //dependencies -using System; -using System.Collections.Generic; -using System.Net.Http; -using System.Net.Http.Headers; -using System.Threading.Tasks; using Dapr.Client; -using Microsoft.AspNetCore.Mvc; -using System.Threading; //code namespace EventService @@ -201,22 +194,13 @@ namespace EventService { static async Task Main(string[] args) { - //Calling service multiple times with 5 seconds gap in between the calls - while(true) { - System.Threading.Thread.Sleep(5000); - Random random = new Random(); - int orderId = random.Next(1,1000); - - CancellationTokenSource source = new CancellationTokenSource(); - CancellationToken cancellationToken = source.Token; - //Using Dapr SDK to invoke a method - using var client = new DaprClientBuilder().Build(); - var result = client.CreateInvokeMethodRequest(HttpMethod.Get, "checkout", "checkout/" + orderId, cancellationToken); - await client.InvokeMethodAsync(result); - - Console.WriteLine("Order requested: " + orderId); - Console.WriteLine("Result: " + result); - } + int orderId = 100; + CancellationTokenSource source = new CancellationTokenSource(); + CancellationToken cancellationToken = source.Token; + //Using Dapr SDK to invoke a method + using var client = new DaprClientBuilder().Build(); + var result = client.CreateInvokeMethodRequest(HttpMethod.Get, "checkout", "checkout/" + orderId, cancellationToken); + await client.InvokeMethodAsync(result); } } } @@ -232,40 +216,21 @@ namespace EventService import io.dapr.client.DaprClient; import io.dapr.client.DaprClientBuilder; import io.dapr.client.domain.HttpExtension; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.Random; -import java.util.concurrent.TimeUnit; //code @SpringBootApplication public class OrderProcessingServiceApplication { - - private static final Logger log = LoggerFactory.getLogger(OrderProcessingServiceApplication.class); - - public static void main(String[] args) throws InterruptedException{ - - //Calling service multiple times with 5 seconds gap in between the calls - while(true) { - TimeUnit.MILLISECONDS.sleep(5000); - Random random = new Random(); - int orderId = random.nextInt(1000-1) + 1; - - //Using Dapr SDK to invoke a method - DaprClient client = new DaprClientBuilder().build(); - var result = client.invokeMethod( - "checkout", - "checkout/" + orderId, - null, - HttpExtension.GET, - String.class - ); - - log.info("Order requested: " + orderId); - log.info("Result: " + result); - } + public static void main(String[] args) throws InterruptedException { + int orderId = 100; + //Using Dapr SDK to invoke a method + DaprClient client = new DaprClientBuilder().build(); + var result = client.invokeMethod( + "checkout", + "checkout/" + orderId, + null, + HttpExtension.GET, + String.class + ); } } @@ -276,31 +241,18 @@ public class OrderProcessingServiceApplication { ```python #dependencies -import random -from time import sleep -import requests -import logging from dapr.clients import DaprClient #code -logging.basicConfig(level = logging.INFO) - -#Calling service multiple times with 5 seconds gap in between the calls -while True: - sleep(random.randrange(50, 5000) / 1000) - orderId = random.randint(1, 1000) - - #Using Dapr SDK to invoke a method - with DaprClient() as client: - result = client.invoke_method( - "checkout", - f"checkout/{orderId}", - data=b'', - http_verb="GET" - ) - logging.basicConfig(level = logging.INFO) - logging.info('Order requested: ' + str(orderId)) - logging.info('Result: ' + str(result)) +orderId = 100 +#Using Dapr SDK to invoke a method +with DaprClient() as client: + result = client.invoke_method( + "checkout", + f"checkout/{orderId}", + data=b'', + http_verb="GET" + ) ``` {{% /codetab %}} @@ -310,10 +262,6 @@ while True: //dependencies import ( - "context" - "log" - "math/rand" - "time" "strconv" dapr "github.com/dapr/go-sdk/client" @@ -321,25 +269,15 @@ import ( //code func main() { - - //Calling service multiple times with 5 seconds gap in between the calls - for i := 0; i < 10; i++ { - time.Sleep(5000) - orderId := rand.Intn(1000-1) + 1 - - //Using Dapr SDK to invoke a method - client, err := dapr.NewClient() - if err != nil { - panic(err) - } - defer client.Close() - ctx := context.Background() - result, err := client.InvokeMethod(ctx, "checkout", "checkout/" + strconv.Itoa(orderId), "get") - - log.Println("Order requested: " + strconv.Itoa(orderId)) - log.Println("Result: ") - log.Println(result) - } + orderId := 100 + //Using Dapr SDK to invoke a method + client, err := dapr.NewClient() + if err != nil { + panic(err) + } + defer client.Close() + ctx := context.Background() + result, err := client.InvokeMethod(ctx, "checkout", "checkout/" + strconv.Itoa(orderId), "get") } ``` @@ -351,27 +289,14 @@ func main() { //dependencies import { DaprClient, HttpMethod, CommunicationProtocolEnum } from 'dapr-client'; -const daprHost = "127.0.0.1"; - //code +const daprHost = "127.0.0.1"; + var main = function() { - - //Calling service multiple times with 5 seconds gap in between the calls - for(var i=0;i<10;i++) { - sleep(5000); - var orderId = Math.floor(Math.random() * (1000 - 1) + 1); - - //Using Dapr SDK to invoke a method - const client = new DaprClient(daprHost, process.env.DAPR_HTTP_PORT, CommunicationProtocolEnum.HTTP); - const result = await client.invoker.invoke('checkout' , "checkout/" + orderId , HttpMethod.GET); - - console.log("Order requested: " + orderId); - console.log("Result: " + result); - } -} - -function sleep(ms) { - return new Promise(resolve => setTimeout(resolve, ms)); + var orderId = 100; + //Using Dapr SDK to invoke a method + const client = new DaprClient(daprHost, process.env.DAPR_HTTP_PORT, CommunicationProtocolEnum.HTTP); + const result = await client.invoker.invoke('checkout' , "checkout/" + orderId , HttpMethod.GET); } main(); diff --git a/daprdocs/content/en/developing-applications/building-blocks/state-management/howto-get-save-state.md b/daprdocs/content/en/developing-applications/building-blocks/state-management/howto-get-save-state.md index ab784b559..89839db12 100644 --- a/daprdocs/content/en/developing-applications/building-blocks/state-management/howto-get-save-state.md +++ b/daprdocs/content/en/developing-applications/building-blocks/state-management/howto-get-save-state.md @@ -81,15 +81,7 @@ Below are code examples that leverage Dapr SDKs for saving and retrieving a sing ```csharp //dependencies -using System; -using System.Collections.Generic; -using System.Net.Http; -using System.Net.Http.Headers; -using System.Threading.Tasks; using Dapr.Client; -using Microsoft.AspNetCore.Mvc; -using System.Threading; -using System.Text.Json; //code namespace EventService @@ -100,26 +92,19 @@ namespace EventService { string DAPR_STORE_NAME = "statestore"; - //Calling service multiple times with 5 seconds gap in between the calls - while(true) { - System.Threading.Thread.Sleep(5000); - Random random = new Random(); - int orderId = random.Next(1,1000); - - //Using Dapr SDK to save and get state - using var client = new DaprClientBuilder().Build(); - await client.SaveStateAsync(DAPR_STORE_NAME, "order_1", orderId.ToString()); - await client.SaveStateAsync(DAPR_STORE_NAME, "order_2", orderId.ToString()); - var result = await client.GetStateAsync(DAPR_STORE_NAME, orderId.ToString()); - Console.WriteLine("Result after get: " + result); - } + int orderId = 100; + //Using Dapr SDK to save and get state + using var client = new DaprClientBuilder().Build(); + await client.SaveStateAsync(DAPR_STORE_NAME, "order_1", orderId.ToString()); + await client.SaveStateAsync(DAPR_STORE_NAME, "order_2", orderId.ToString()); + var result = await client.GetStateAsync(DAPR_STORE_NAME, orderId.ToString()); } } } ``` -Once saved run the following command to launch a Dapr sidecar and run the application: +Navigate to the directory containing the above code, then run the following command to launch a Dapr sidecar and run the application: ```bash dapr run --app-id orderprocessing --app-port 6001 --dapr-http-port 3601 --dapr-grpc-port 60001 dotnet run @@ -136,13 +121,7 @@ dapr run --app-id orderprocessing --app-port 6001 --dapr-http-port 3601 --dapr-g import io.dapr.client.DaprClient; import io.dapr.client.DaprClientBuilder; import io.dapr.client.domain.State; -import io.dapr.client.domain.TransactionalStateOperation; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import reactor.core.publisher.Mono; -import java.util.Random; -import java.util.concurrent.TimeUnit; //code @SpringBootApplication @@ -150,28 +129,21 @@ public class OrderProcessingServiceApplication { private static final Logger log = LoggerFactory.getLogger(OrderProcessingServiceApplication.class); - public static void main(String[] args) throws InterruptedException{ + public static void main(String[] args) throws InterruptedException { String STATE_STORE_NAME = "statestore"; - //Calling service multiple times with 5 seconds gap in between the calls - while(true) { - TimeUnit.MILLISECONDS.sleep(5000); - Random random = new Random(); - int orderId = random.nextInt(1000-1) + 1; - - //Using Dapr SDK to save and get state - DaprClient client = new DaprClientBuilder().build(); - client.saveState(STATE_STORE_NAME, "order_1", Integer.toString(orderId)).block(); - client.saveState(STATE_STORE_NAME, "order_2", Integer.toString(orderId)).block(); - Mono> result = client.getState(STATE_STORE_NAME, "order_1", String.class); - log.info("Result after get" + result); - } + int orderId = 100; + //Using Dapr SDK to save and get state + DaprClient client = new DaprClientBuilder().build(); + client.saveState(STATE_STORE_NAME, "order_1", Integer.toString(orderId)).block(); + client.saveState(STATE_STORE_NAME, "order_2", Integer.toString(orderId)).block(); + Mono> result = client.getState(STATE_STORE_NAME, "order_1", String.class); } } ``` -Once saved run the following command to launch a Dapr sidecar and run the application: +Navigate to the directory containing the above code, then run the following command to launch a Dapr sidecar and run the application: ```bash dapr run --app-id orderprocessing --app-port 6001 --dapr-http-port 3601 --dapr-grpc-port 60001 mvn spring-boot:run @@ -185,33 +157,23 @@ dapr run --app-id orderprocessing --app-port 6001 --dapr-http-port 3601 --dapr-g ```python #dependencies -import random -from time import sleep -import requests -import logging from dapr.clients import DaprClient -from dapr.clients.grpc._state import StateItem -from dapr.clients.grpc._request import TransactionalStateOperation, TransactionOperationType #code logging.basicConfig(level = logging.INFO) DAPR_STORE_NAME = "statestore" -#Calling service multiple times with 5 seconds gap in between the calls -while True: - sleep(random.randrange(50, 5000) / 1000) - orderId = random.randint(1, 1000) - - #Using Dapr SDK to save and get state - with DaprClient() as client: - client.save_state(DAPR_STORE_NAME, "order_1", str(orderId)) - result = client.get_state(DAPR_STORE_NAME, "order_1") - logging.info('Result after get: ' + str(result)) +orderId = 100 +#Using Dapr SDK to save and get state +with DaprClient() as client: + client.save_state(DAPR_STORE_NAME, "order_1", str(orderId)) + result = client.get_state(DAPR_STORE_NAME, "order_1") + logging.info('Result after get: ' + str(result)) ``` -Once saved run the following command to launch a Dapr sidecar and run the application: +Navigate to the directory containing the above code, then run the following command to launch a Dapr sidecar and run the application: ```bash dapr run --app-id orderprocessing --app-port 6001 --dapr-http-port 3601 --dapr-grpc-port 60001 -- python3 OrderProcessingService.py @@ -240,36 +202,29 @@ func main() { STATE_STORE_NAME := "statestore" - //Calling service multiple times with 5 seconds gap in between the calls - for i := 0; i < 10; i++ { - time.Sleep(5000) - orderId := rand.Intn(1000-1) + 1 + orderId := 100 - //Using Dapr SDK to save and get state - client, err := dapr.NewClient() - if err != nil { - panic(err) - } - defer client.Close() - ctx := context.Background() + //Using Dapr SDK to save and get state + client, err := dapr.NewClient() + if err != nil { + panic(err) + } + defer client.Close() + ctx := context.Background() - if err := client.SaveState(ctx, STATE_STORE_NAME, "order_1", []byte(strconv.Itoa(orderId))); err != nil { - panic(err) - } - - result, err := client.GetState(ctx, STATE_STORE_NAME, "order_1") - if err != nil { - panic(err) - } - - log.Println("Result after get: ") - log.Println(result) - } + if err := client.SaveState(ctx, STATE_STORE_NAME, "order_1", []byte(strconv.Itoa(orderId))); err != nil { + panic(err) + } + + result, err := client.GetState(ctx, STATE_STORE_NAME, "order_1") + if err != nil { + panic(err) + } } ``` -Once saved run the following command to launch a Dapr sidecar and run the application: +Navigate to the directory containing the above code, then run the following command to launch a Dapr sidecar and run the application: ```bash dapr run --app-id orderprocessing --app-port 6001 --dapr-http-port 3601 --dapr-grpc-port 60001 go run OrderProcessingService.go @@ -291,37 +246,27 @@ const daprHost = "127.0.0.1"; var main = function() { const STATE_STORE_NAME = "statestore"; - //Calling service multiple times with 5 seconds gap in between the calls - for(var i=0;i<10;i++) { - sleep(5000); - var orderId = Math.floor(Math.random() * (1000 - 1) + 1); - - //Using Dapr SDK to save and get state - const client = new DaprClient(daprHost, process.env.DAPR_HTTP_PORT, CommunicationProtocolEnum.HTTP); - await client.state.save(STATE_STORE_NAME, [ - { - key: "order_1", - value: orderId.toString() - }, - { - key: "order_2", - value: orderId.toString() - } - ]); - var result = await client.state.get(STATE_STORE_NAME, "order_1"); - console.log("Result after get: " + result); - } -} - -function sleep(ms) { - return new Promise(resolve => setTimeout(resolve, ms)); + var orderId = 100; + //Using Dapr SDK to save and get state + const client = new DaprClient(daprHost, process.env.DAPR_HTTP_PORT, CommunicationProtocolEnum.HTTP); + await client.state.save(STATE_STORE_NAME, [ + { + key: "order_1", + value: orderId.toString() + }, + { + key: "order_2", + value: orderId.toString() + } + ]); + var result = await client.state.get(STATE_STORE_NAME, "order_1"); } main(); ``` -Once saved run the following command to launch a Dapr sidecar and run the application: +Navigate to the directory containing the above code, then run the following command to launch a Dapr sidecar and run the application: ```bash dapr run --app-id orderprocessing --app-port 6001 --dapr-http-port 3601 --dapr-grpc-port 60001 npm start @@ -347,7 +292,7 @@ Now get the state you just saved: curl http://localhost:3601/v1.0/state/statestore/order_1 ``` -You can also restart your sidecar and try retrieving state again to see that state persists separate from the app. +Restart your sidecar and try retrieving state again to observe that state persists separately from the app. {{% /codetab %}} {{% codetab %}} @@ -368,7 +313,7 @@ Now get the state you just saved: Invoke-RestMethod -Uri 'http://localhost:3601/v1.0/state/statestore/order_1' ``` -You can also restart your sidecar and try retrieving state again to see that state persists separate from the app. +Restart your sidecar and try retrieving state again to observe that state persists separately from the app. {{% /codetab %}} @@ -386,15 +331,7 @@ Below are code examples that leverage Dapr SDKs for deleting the state. ```csharp //dependencies -using System; -using System.Collections.Generic; -using System.Net.Http; -using System.Net.Http.Headers; -using System.Threading.Tasks; using Dapr.Client; -using Microsoft.AspNetCore.Mvc; -using System.Threading; -using System.Text.Json; //code namespace EventService @@ -413,7 +350,7 @@ namespace EventService ``` -Once saved run the following command to launch a Dapr sidecar and run the application: +Navigate to the directory containing the above code, then run the following command to launch a Dapr sidecar and run the application: ```bash dapr run --app-id orderprocessing --app-port 6001 --dapr-http-port 3601 --dapr-grpc-port 60001 dotnet run @@ -429,20 +366,10 @@ dapr run --app-id orderprocessing --app-port 6001 --dapr-http-port 3601 --dapr-g //dependencies import io.dapr.client.DaprClient; import io.dapr.client.DaprClientBuilder; -import io.dapr.client.domain.State; -import io.dapr.client.domain.TransactionalStateOperation; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import java.util.Random; -import java.util.concurrent.TimeUnit; //code @SpringBootApplication public class OrderProcessingServiceApplication { - - private static final Logger log = LoggerFactory.getLogger(OrderProcessingServiceApplication.class); - public static void main(String[] args) throws InterruptedException{ String STATE_STORE_NAME = "statestore"; @@ -455,7 +382,7 @@ public class OrderProcessingServiceApplication { ``` -Once saved run the following command to launch a Dapr sidecar and run the application: +Navigate to the directory containing the above code, then run the following command to launch a Dapr sidecar and run the application: ```bash dapr run --app-id orderprocessing --app-port 6001 --dapr-http-port 3601 --dapr-grpc-port 60001 mvn spring-boot:run @@ -469,12 +396,6 @@ dapr run --app-id orderprocessing --app-port 6001 --dapr-http-port 3601 --dapr-g ```python #dependencies -import random -from time import sleep -import requests -import logging -from dapr.clients import DaprClient -from dapr.clients.grpc._state import StateItem from dapr.clients.grpc._request import TransactionalStateOperation, TransactionOperationType #code @@ -488,7 +409,7 @@ with DaprClient() as client: ``` -Once saved run the following command to launch a Dapr sidecar and run the application: +Navigate to the directory containing the above code, then run the following command to launch a Dapr sidecar and run the application: ```bash dapr run --app-id orderprocessing --app-port 6001 --dapr-http-port 3601 --dapr-grpc-port 60001 -- python3 OrderProcessingService.py @@ -528,7 +449,7 @@ func main() { ``` -Once saved run the following command to launch a Dapr sidecar and run the application: +Navigate to the directory containing the above code, then run the following command to launch a Dapr sidecar and run the application: ```bash dapr run --app-id orderprocessing --app-port 6001 --dapr-http-port 3601 --dapr-grpc-port 60001 go run OrderProcessingService.go @@ -555,15 +476,11 @@ var main = function() { await client.state.delete(STATE_STORE_NAME, "order_1"); } -function sleep(ms) { - return new Promise(resolve => setTimeout(resolve, ms)); -} - main(); ``` -Once saved run the following command to launch a Dapr sidecar and run the application: +Navigate to the directory containing the above code, then run the following command to launch a Dapr sidecar and run the application: ```bash dapr run --app-id orderprocessing --app-port 6001 --dapr-http-port 3601 --dapr-grpc-port 60001 npm start @@ -572,7 +489,7 @@ dapr run --app-id orderprocessing --app-port 6001 --dapr-http-port 3601 --dapr-g {{% /codetab %}} {{% codetab %}} -With the same dapr instance running from above run: +With the same Dapr instance running from above run: ```bash curl -X DELETE 'http://localhost:3601/v1.0/state/statestore/order_1' ``` @@ -580,7 +497,7 @@ Try getting state again and note that no value is returned. {{% /codetab %}} {{% codetab %}} -With the same dapr instance running from above run: +With the same Dapr instance running from above run: ```powershell Invoke-RestMethod -Method Delete -Uri 'http://localhost:3601/v1.0/state/statestore/order_1' ``` @@ -603,13 +520,6 @@ Below are code examples that leverage Dapr SDKs for saving and retrieving multip import io.dapr.client.DaprClient; import io.dapr.client.DaprClientBuilder; import io.dapr.client.domain.State; -import io.dapr.client.domain.TransactionalStateOperation; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import reactor.core.publisher.Mono; -import java.util.Random; -import java.util.concurrent.TimeUnit; //code @SpringBootApplication @@ -620,23 +530,17 @@ public class OrderProcessingServiceApplication { public static void main(String[] args) throws InterruptedException{ String STATE_STORE_NAME = "statestore"; - //Calling service multiple times with 5 seconds gap in between the calls - while(true) { - TimeUnit.MILLISECONDS.sleep(5000); - Random random = new Random(); - int orderId = random.nextInt(1000-1) + 1; - - //Using Dapr SDK to retrieve multiple states - DaprClient client = new DaprClientBuilder().build(); - Mono>> resultBulk = client.getBulkState(STATE_STORE_NAME, - Arrays.asList("order_1", "order_2"), String.class); - } + int orderId = 100; + //Using Dapr SDK to retrieve multiple states + DaprClient client = new DaprClientBuilder().build(); + Mono>> resultBulk = client.getBulkState(STATE_STORE_NAME, + Arrays.asList("order_1", "order_2"), String.class); } } ``` -Once saved run the following command to launch a Dapr sidecar and run the application: +Navigate to the directory containing the above code, then run the following command to launch a Dapr sidecar and run the application: ```bash dapr run --app-id orderprocessing --app-port 6001 --dapr-http-port 3601 --dapr-grpc-port 60001 mvn spring-boot:run @@ -650,33 +554,24 @@ dapr run --app-id orderprocessing --app-port 6001 --dapr-http-port 3601 --dapr-g ```python #dependencies -import random -from time import sleep -import requests -import logging from dapr.clients import DaprClient from dapr.clients.grpc._state import StateItem -from dapr.clients.grpc._request import TransactionalStateOperation, TransactionOperationType #code logging.basicConfig(level = logging.INFO) DAPR_STORE_NAME = "statestore" -#Calling service multiple times with 5 seconds gap in between the calls -while True: - sleep(random.randrange(50, 5000) / 1000) - orderId = random.randint(1, 1000) - - #Using Dapr SDK to save and retrieve multiple states - with DaprClient() as client: - client.save_bulk_state(store_name=DAPR_STORE_NAME, states=[StateItem(key="order_2", value=str(orderId))]) - result = client.get_bulk_state(store_name=DAPR_STORE_NAME, keys=["order_1", "order_2"], states_metadata={"metakey": "metavalue"}).items - logging.info('Result after get bulk: ' + str(result)) +orderId = 100 +#Using Dapr SDK to save and retrieve multiple states +with DaprClient() as client: + client.save_bulk_state(store_name=DAPR_STORE_NAME, states=[StateItem(key="order_2", value=str(orderId))]) + result = client.get_bulk_state(store_name=DAPR_STORE_NAME, keys=["order_1", "order_2"], states_metadata={"metakey": "metavalue"}).items + logging.info('Result after get bulk: ' + str(result)) ``` -Once saved run the following command to launch a Dapr sidecar and run the application: +Navigate to the directory containing the above code, then run the following command to launch a Dapr sidecar and run the application: ```bash dapr run --app-id orderprocessing --app-port 6001 --dapr-http-port 3601 --dapr-grpc-port 60001 -- python3 OrderProcessingService.py @@ -699,37 +594,27 @@ const daprHost = "127.0.0.1"; var main = function() { const STATE_STORE_NAME = "statestore"; - //Calling service multiple times with 5 seconds gap in between the calls - for(var i=0;i<10;i++) { - sleep(5000); - var orderId = Math.floor(Math.random() * (1000 - 1) + 1); - - //Using Dapr SDK to save and retrieve multiple states - const client = new DaprClient(daprHost, process.env.DAPR_HTTP_PORT, CommunicationProtocolEnum.HTTP); - await client.state.save(STATE_STORE_NAME, [ - { - key: "order_1", - value: orderId.toString() - }, - { - key: "order_2", - value: orderId.toString() - } - ]); - result = await client.state.getBulk(STATE_STORE_NAME, ["order_1", "order_2"]); - console.log("Result after get bulk: " + result); - } -} - -function sleep(ms) { - return new Promise(resolve => setTimeout(resolve, ms)); + var orderId = 100; + //Using Dapr SDK to save and retrieve multiple states + const client = new DaprClient(daprHost, process.env.DAPR_HTTP_PORT, CommunicationProtocolEnum.HTTP); + await client.state.save(STATE_STORE_NAME, [ + { + key: "order_1", + value: orderId.toString() + }, + { + key: "order_2", + value: orderId.toString() + } + ]); + result = await client.state.getBulk(STATE_STORE_NAME, ["order_1", "order_2"]); } main(); ``` -Once saved run the following command to launch a Dapr sidecar and run the application: +Navigate to the directory containing the above code, then run the following command to launch a Dapr sidecar and run the application: ```bash dapr run --app-id orderprocessing --app-port 6001 --dapr-http-port 3601 --dapr-grpc-port 60001 npm start @@ -738,7 +623,7 @@ dapr run --app-id orderprocessing --app-port 6001 --dapr-http-port 3601 --dapr-g {{% /codetab %}} {{% codetab %}} -With the same dapr instance running from above save two key/value pairs into your statestore: +With the same Dapr instance running from above save two key/value pairs into your statestore: ```bash curl -X POST -H "Content-Type: application/json" -d '[{ "key": "order_1", "value": "250"}, { "key": "order_2", "value": "550"}]' http://localhost:3601/v1.0/state/statestore ``` @@ -750,7 +635,7 @@ curl -X POST -H "Content-Type: application/json" -d '{"keys":["order_1", "order_ {{% /codetab %}} {{% codetab %}} -With the same dapr instance running from above save two key/value pairs into your statestore: +With the same Dapr instance running from above save two key/value pairs into your statestore: ```powershell Invoke-RestMethod -Method Post -ContentType 'application/json' -Body '[{ "key": "order_1", "value": "250"}, { "key": "order_2", "value": "550"}]' -Uri 'http://localhost:3601/v1.0/state/statestore' ``` @@ -779,15 +664,7 @@ Below are code examples that leverage Dapr SDKs for performing state transaction ```csharp //dependencies -using System; -using System.Collections.Generic; -using System.Net.Http; -using System.Net.Http.Headers; -using System.Threading.Tasks; using Dapr.Client; -using Microsoft.AspNetCore.Mvc; -using System.Threading; -using System.Text.Json; //code namespace EventService @@ -797,30 +674,25 @@ namespace EventService static async Task Main(string[] args) { string DAPR_STORE_NAME = "statestore"; - //Calling service multiple times with 5 seconds gap in between the calls - while(true) { - System.Threading.Thread.Sleep(5000); - Random random = new Random(); - int orderId = random.Next(1,1000); - - //Using Dapr SDK to perform the state transactions - using var client = new DaprClientBuilder().Build(); - var requests = new List() - { - new StateTransactionRequest("order_3", JsonSerializer.SerializeToUtf8Bytes(orderId.ToString()), StateOperationType.Upsert), - new StateTransactionRequest("order_2", null, StateOperationType.Delete) - }; - CancellationTokenSource source = new CancellationTokenSource(); - CancellationToken cancellationToken = source.Token; - await client.ExecuteStateTransactionAsync(DAPR_STORE_NAME, requests, cancellationToken: cancellationToken); - } + + int orderId = 100; + //Using Dapr SDK to perform the state transactions + using var client = new DaprClientBuilder().Build(); + var requests = new List() + { + new StateTransactionRequest("order_3", JsonSerializer.SerializeToUtf8Bytes(orderId.ToString()), StateOperationType.Upsert), + new StateTransactionRequest("order_2", null, StateOperationType.Delete) + }; + CancellationTokenSource source = new CancellationTokenSource(); + CancellationToken cancellationToken = source.Token; + await client.ExecuteStateTransactionAsync(DAPR_STORE_NAME, requests, cancellationToken: cancellationToken); } } } ``` -Once saved run the following command to launch a Dapr sidecar and run the application: +Navigate to the directory containing the above code, then run the following command to launch a Dapr sidecar and run the application: ```bash dapr run --app-id orderprocessing --app-port 6001 --dapr-http-port 3601 --dapr-grpc-port 60001 dotnet run @@ -838,15 +710,7 @@ import io.dapr.client.DaprClient; import io.dapr.client.DaprClientBuilder; import io.dapr.client.domain.State; import io.dapr.client.domain.TransactionalStateOperation; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import reactor.core.publisher.Mono; -import java.util.Random; -import java.util.concurrent.TimeUnit; + //code @SpringBootApplication @@ -857,27 +721,21 @@ public class OrderProcessingServiceApplication { public static void main(String[] args) throws InterruptedException{ String STATE_STORE_NAME = "statestore"; - //Calling service multiple times with 5 seconds gap in between the calls - while(true) { - TimeUnit.MILLISECONDS.sleep(5000); - Random random = new Random(); - int orderId = random.nextInt(1000-1) + 1; - - //Using Dapr SDK to perform the state transactions - DaprClient client = new DaprClientBuilder().build(); - List> operationList = new ArrayList<>(); - operationList.add(new TransactionalStateOperation<>(TransactionalStateOperation.OperationType.UPSERT, - new State<>("order_3", Integer.toString(orderId), ""))); - operationList.add(new TransactionalStateOperation<>(TransactionalStateOperation.OperationType.DELETE, - new State<>("order_2"))); - client.executeStateTransaction(STATE_STORE_NAME, operationList).block(); - } + int orderId = 100; + //Using Dapr SDK to perform the state transactions + DaprClient client = new DaprClientBuilder().build(); + List> operationList = new ArrayList<>(); + operationList.add(new TransactionalStateOperation<>(TransactionalStateOperation.OperationType.UPSERT, + new State<>("order_3", Integer.toString(orderId), ""))); + operationList.add(new TransactionalStateOperation<>(TransactionalStateOperation.OperationType.DELETE, + new State<>("order_2"))); + client.executeStateTransaction(STATE_STORE_NAME, operationList).block(); } } ``` -Once saved run the following command to launch a Dapr sidecar and run the application: +Navigate to the directory containing the above code, then run the following command to launch a Dapr sidecar and run the application: ```bash dapr run --app-id orderprocessing --app-port 6001 --dapr-http-port 3601 --dapr-grpc-port 60001 mvn spring-boot:run @@ -891,10 +749,6 @@ dapr run --app-id orderprocessing --app-port 6001 --dapr-http-port 3601 --dapr-g ```python #dependencies -import random -from time import sleep -import requests -import logging from dapr.clients import DaprClient from dapr.clients.grpc._state import StateItem from dapr.clients.grpc._request import TransactionalStateOperation, TransactionOperationType @@ -904,29 +758,25 @@ logging.basicConfig(level = logging.INFO) DAPR_STORE_NAME = "statestore" -#Calling service multiple times with 5 seconds gap in between the calls -while True: - sleep(random.randrange(50, 5000) / 1000) - orderId = random.randint(1, 1000) - - #Using Dapr SDK to perform the state transactions - with DaprClient() as client: - client.execute_state_transaction(store_name=DAPR_STORE_NAME, operations=[ - TransactionalStateOperation( - operation_type=TransactionOperationType.upsert, - key="order_3", - data=str(orderId)), - TransactionalStateOperation(key="order_3", data=str(orderId)), - TransactionalStateOperation( - operation_type=TransactionOperationType.delete, - key="order_2", - data=str(orderId)), - TransactionalStateOperation(key="order_2", data=str(orderId)) - ]) +orderId = 100 +#Using Dapr SDK to perform the state transactions +with DaprClient() as client: + client.execute_state_transaction(store_name=DAPR_STORE_NAME, operations=[ + TransactionalStateOperation( + operation_type=TransactionOperationType.upsert, + key="order_3", + data=str(orderId)), + TransactionalStateOperation(key="order_3", data=str(orderId)), + TransactionalStateOperation( + operation_type=TransactionOperationType.delete, + key="order_2", + data=str(orderId)), + TransactionalStateOperation(key="order_2", data=str(orderId)) + ]) ``` -Once saved run the following command to launch a Dapr sidecar and run the application: +Navigate to the directory containing the above code, then run the following command to launch a Dapr sidecar and run the application: ```bash dapr run --app-id orderprocessing --app-port 6001 --dapr-http-port 3601 --dapr-grpc-port 60001 -- python3 OrderProcessingService.py @@ -948,40 +798,31 @@ const daprHost = "127.0.0.1"; var main = function() { const STATE_STORE_NAME = "statestore"; - //Calling service multiple times with 5 seconds gap in between the calls - for(var i=0;i<10;i++) { - sleep(5000); - var orderId = Math.floor(Math.random() * (1000 - 1) + 1); - - //Using Dapr SDK to save and retrieve multiple states - const client = new DaprClient(daprHost, process.env.DAPR_HTTP_PORT, CommunicationProtocolEnum.HTTP); - await client.state.transaction(STATE_STORE_NAME, [ - { - operation: "upsert", - request: { - key: "order_3", - value: orderId.toString() - } - }, - { - operation: "delete", - request: { - key: "order_2" - } + var orderId = 100; + //Using Dapr SDK to save and retrieve multiple states + const client = new DaprClient(daprHost, process.env.DAPR_HTTP_PORT, CommunicationProtocolEnum.HTTP); + await client.state.transaction(STATE_STORE_NAME, [ + { + operation: "upsert", + request: { + key: "order_3", + value: orderId.toString() } - ]); - } -} - -function sleep(ms) { - return new Promise(resolve => setTimeout(resolve, ms)); + }, + { + operation: "delete", + request: { + key: "order_2" + } + } + ]); } main(); ``` -Once saved run the following command to launch a Dapr sidecar and run the application: +Navigate to the directory containing the above code, then run the following command to launch a Dapr sidecar and run the application: ```bash dapr run --app-id orderprocessing --app-port 6001 --dapr-http-port 3601 --dapr-grpc-port 60001 npm start @@ -990,7 +831,7 @@ dapr run --app-id orderprocessing --app-port 6001 --dapr-http-port 3601 --dapr-g {{% /codetab %}} {{% codetab %}} -With the same dapr instance running from above perform two state transactions: +With the same Dapr instance running from above perform two state transactions: ```bash curl -X POST -H "Content-Type: application/json" -d '{"operations": [{"operation":"upsert", "request": {"key": "order_1", "value": "250"}}, {"operation":"delete", "request": {"key": "order_2"}}]}' http://localhost:3601/v1.0/state/statestore/transaction ``` @@ -1002,7 +843,7 @@ curl -X POST -H "Content-Type: application/json" -d '{"keys":["order_1", "order_ {{% /codetab %}} {{% codetab %}} -With the same dapr instance running from above save two key/value pairs into your statestore: +With the same Dapr instance running from above save two key/value pairs into your statestore: ```powershell Invoke-RestMethod -Method Post -ContentType 'application/json' -Body '{"operations": [{"operation":"upsert", "request": {"key": "order_1", "value": "250"}}, {"operation":"delete", "request": {"key": "order_2"}}]}' -Uri 'http://localhost:3601/v1.0/state/statestore' ``` diff --git a/daprdocs/content/en/developing-applications/building-blocks/state-management/state-store-ttl.md b/daprdocs/content/en/developing-applications/building-blocks/state-management/state-store-ttl.md index de57e9aa1..22a8e8293 100644 --- a/daprdocs/content/en/developing-applications/building-blocks/state-management/state-store-ttl.md +++ b/daprdocs/content/en/developing-applications/building-blocks/state-management/state-store-ttl.md @@ -51,7 +51,7 @@ with DaprClient() as client: ``` -Once saved run the following command to launch a Dapr sidecar and run the application: +Navigate to the directory containing the above code, then run the following command to launch a Dapr sidecar and run the application: ```bash dapr run --app-id orderprocessing --app-port 6001 --dapr-http-port 3601 --dapr-grpc-port 60001 -- python3 OrderProcessingService.py From e4af246e04f968fb969826d1ff81f8cad5024494 Mon Sep 17 00:00:00 2001 From: Will Tsai Date: Tue, 30 Nov 2021 09:30:11 -0800 Subject: [PATCH 12/30] Deleting redundant page app-configuration-overview.md --- .../app-configuration-overview.md | 18 ------------------ 1 file changed, 18 deletions(-) delete mode 100644 daprdocs/content/en/developing-applications/building-blocks/configuration/app-configuration-overview.md diff --git a/daprdocs/content/en/developing-applications/building-blocks/configuration/app-configuration-overview.md b/daprdocs/content/en/developing-applications/building-blocks/configuration/app-configuration-overview.md deleted file mode 100644 index 5fd34c9bb..000000000 --- a/daprdocs/content/en/developing-applications/building-blocks/configuration/app-configuration-overview.md +++ /dev/null @@ -1,18 +0,0 @@ ---- -type: docs -title: "Configuration overview" -linkTitle: "Configuration overview" -weight: 1000 -description: "Use Dapr to get and watch application configuration" ---- - -Consuming application configuration is a common task when writing applications and frequently configuration stores are used to manage this configuration data. A configuration item is often dynamic in nature and is tightly coupled to the needs of the application that consumes it. For example, common uses for application configuration include names of secrets that need to be retrieved, different identifiers, partition or consumer IDs, names of databased to connect to etc. These configuration items are typically stored as key-value items in a database. - -Dapr provides a [State Management API]({{}}) that is based on key-value stores. However, application configuration can be changed by either developers or operators at runtime and the developer needs to be notified of these changes in order to take the required action and load the new configuration. Also the configuration data may want to be read only. Dapr's Configuration API allows developers to consume configuration items that are returned as key/value pair and subscribe to changes whenever a configuration item changes. - -*This API is currently in `Alpha state` and only available on gRPC. An HTTP1.1 supported version with this URL `/v1.0/configuration` will be available before the API becomes stable.* - -## References - -- [How-To: Manage application configuration]({{< ref howto-manage-configuration.md >}}) - From dc460db372e759cac613cca05dcef5edb0fefdd6 Mon Sep 17 00:00:00 2001 From: Will Tsai Date: Tue, 30 Nov 2021 11:21:25 -0800 Subject: [PATCH 13/30] fix Jetstream broken link --- .../components-reference/supported-pubsub/setup-jetstream.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/daprdocs/content/en/reference/components-reference/supported-pubsub/setup-jetstream.md b/daprdocs/content/en/reference/components-reference/supported-pubsub/setup-jetstream.md index 61e4711cb..791a2f02b 100644 --- a/daprdocs/content/en/reference/components-reference/supported-pubsub/setup-jetstream.md +++ b/daprdocs/content/en/reference/components-reference/supported-pubsub/setup-jetstream.md @@ -86,7 +86,7 @@ with NATS, find the service with: `kubectl get svc my-nats`. - [Basic schema for a Dapr component]({{< ref component-schema >}}) - Read [this guide]({{< ref "howto-publish-subscribe.md#step-2-publish-a-topic" >}}) for instructions on configuring pub/sub components - [Pub/Sub building block]({{< ref pubsub >}}) -- [JetStream Documentation](https://docs.nats.io/jetstream/jetstream) +- [JetStream Documentation](https://docs.nats.io/nats-concepts/jetstream) - [NATS CLI](https://github.com/nats-io/natscli) From dc878f6ca968aba1b44368de0cdc3aa8bcb573c5 Mon Sep 17 00:00:00 2001 From: Bernd Verst <4535280+berndverst@users.noreply.github.com> Date: Tue, 30 Nov 2021 17:08:02 -0800 Subject: [PATCH 14/30] Cosmos DB components production guidance --- .../supported-bindings/cosmosdb.md | 27 ++++++++++++++++++- .../setup-azure-cosmosdb.md | 11 ++++++++ 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/daprdocs/content/en/reference/components-reference/supported-bindings/cosmosdb.md b/daprdocs/content/en/reference/components-reference/supported-bindings/cosmosdb.md index 163fe8d3d..aaa41d2de 100644 --- a/daprdocs/content/en/reference/components-reference/supported-bindings/cosmosdb.md +++ b/daprdocs/content/en/reference/components-reference/supported-bindings/cosmosdb.md @@ -46,7 +46,7 @@ The above example uses secrets as plain strings. It is recommended to use a secr | masterKey | Y | Output | The CosmosDB account master key | `"master-key"` | | database | Y | Output | The name of the CosmosDB database | `"OrderDb"` | | collection | Y | Output | The name of the container inside the database. | `"Orders"` | -| partitionKey | Y | Output | The name of the partitionKey to extract from the payload and is used in the container | `"OrderId"`, `"message"` | +| partitionKey | Y | Output | The name of the key to extract from the payload (document to be created) that is used as the partition key. This name must match the partition key specified upon creation of the Cosmos DB container. | `"OrderId"`, `"message"` | For more information see [Azure Cosmos DB resource model](https://docs.microsoft.com/azure/cosmos-db/account-databases-containers-items). @@ -56,6 +56,31 @@ This component supports **output binding** with the following operations: - `create` +## Best Practices for Production Use + +Azure Cosmos DB shares a strict metadata request rate limit across all databases in a single Azure Cosmos DB account. New connections to Azure Cosmos DB assume a large percentage of the allowable request rate limit. (See the [CosmosDB documentation](https://docs.microsoft.com/azure/cosmos-db/sql/troubleshoot-request-rate-too-large#recommended-solution-3)) + +Therefore several strategies must be applied to avoid simultaneous new connections to Azure Cosmos DB: + +- Ensure sidecars of applications only load the Azure Cosmos DB component when they require it to avoid unnecessary database connections. This can be done by [scoping your components to specific applications]({{< ref component-scopes.md#application-access-to-components-with-scopes >}}). +- Choose deployment strategies that sequentially deploy or start all applications to minimize bursts in new connections to your Azure Cosmos DB accounts. +- Avoid reusing the same Azure Cosmos DB account for unrelated databases or systems (even outside of Dapr). Distinct Azure Cosmos DB accounts have distinct rate limits. +- Increase the `initTimeout` value to allow the component to retry connecting to Azure Cosmos DB during side car initialization for up to 5 minutes. The default value is `5s` and should be increased. Using Kubernetes increasing this value may also require an update to your [Readiness and Liveness probes](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/). + +```yaml +spec: + type: bindings.azure.cosmosdb + version: v1 + initTimeout: 5m + metadata: +``` + +## Data format + +The **output binding** `create` operation requires the following keys to exist in the payload of every document to be created: +- `id`: a unique ID for the document to be created +- ``: the name of the partition key specified via the `spec.partitionKey` in the component definition. This must also match the partition key specified upon creation of the Cosmos DB container. + ## Related links - [Basic schema for a Dapr component]({{< ref component-schema >}}) diff --git a/daprdocs/content/en/reference/components-reference/supported-state-stores/setup-azure-cosmosdb.md b/daprdocs/content/en/reference/components-reference/supported-state-stores/setup-azure-cosmosdb.md index db53ee78b..a69ad8b7f 100644 --- a/daprdocs/content/en/reference/components-reference/supported-state-stores/setup-azure-cosmosdb.md +++ b/daprdocs/content/en/reference/components-reference/supported-state-stores/setup-azure-cosmosdb.md @@ -64,6 +64,17 @@ In order to setup CosmosDB as a state store, you need the following properties: - **Database**: The name of the database - **Collection**: The name of the collection +## Best Practices for Production Use + +Azure Cosmos DB shares a strict metadata request rate limit across all databases in a single Azure Cosmos DB account. New connections to Azure Cosmos DB assume a large percentage of the allowable request rate limit. (See the [CosmosDB documentation](https://docs.microsoft.com/azure/cosmos-db/sql/troubleshoot-request-rate-too-large#recommended-solution-3)) + +Therefore several strategies must be applied to avoid simultaneous new connections to Azure Cosmos DB: + +- Ensure sidecars of applications only load the Azure Cosmos DB component when they require it to avoid unnecessary database connections. This can be done by [scoping your components to specific applications]({{< ref component-scopes.md#application-access-to-components-with-scopes >}}). +- Choose deployment strategies that sequentially deploy or start all applications to minimize bursts in new connections to your Azure Cosmos DB accounts. +- Avoid reusing the same Azure Cosmos DB account for unrelated databases or systems (even outside of Dapr). Distinct Azure Cosmos DB accounts have distinct rate limits. +- Increase the `initTimeout` value to allow the component to retry connecting to Azure Cosmos DB during side car initialization for up to 5 minutes. The default value is `5s` and should be increased. Using Kubernetes increasing this value may also require an update to your [Readiness and Liveness probes](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/). + ## Data format To use the CosmosDB state store, your data must be sent to Dapr in JSON-serialized. Having it just JSON *serializable* will not work. From 4dd9ea88b082636936d3222b9f560d4437f9b4d6 Mon Sep 17 00:00:00 2001 From: Bernd Verst <4535280+berndverst@users.noreply.github.com> Date: Tue, 30 Nov 2021 17:24:14 -0800 Subject: [PATCH 15/30] Fix link --- .../components-reference/supported-bindings/cosmosdb.md | 2 +- .../supported-state-stores/setup-azure-cosmosdb.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/daprdocs/content/en/reference/components-reference/supported-bindings/cosmosdb.md b/daprdocs/content/en/reference/components-reference/supported-bindings/cosmosdb.md index aaa41d2de..e35d2ea66 100644 --- a/daprdocs/content/en/reference/components-reference/supported-bindings/cosmosdb.md +++ b/daprdocs/content/en/reference/components-reference/supported-bindings/cosmosdb.md @@ -62,7 +62,7 @@ Azure Cosmos DB shares a strict metadata request rate limit across all databases Therefore several strategies must be applied to avoid simultaneous new connections to Azure Cosmos DB: -- Ensure sidecars of applications only load the Azure Cosmos DB component when they require it to avoid unnecessary database connections. This can be done by [scoping your components to specific applications]({{< ref component-scopes.md#application-access-to-components-with-scopes >}}). +- Ensure sidecars of applications only load the Azure Cosmos DB component when they require it to avoid unnecessary database connections. This can be done by [scoping your components to specific applications]({{< ref component-scopes.md >}}#application-access-to-components-with-scopes). - Choose deployment strategies that sequentially deploy or start all applications to minimize bursts in new connections to your Azure Cosmos DB accounts. - Avoid reusing the same Azure Cosmos DB account for unrelated databases or systems (even outside of Dapr). Distinct Azure Cosmos DB accounts have distinct rate limits. - Increase the `initTimeout` value to allow the component to retry connecting to Azure Cosmos DB during side car initialization for up to 5 minutes. The default value is `5s` and should be increased. Using Kubernetes increasing this value may also require an update to your [Readiness and Liveness probes](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/). diff --git a/daprdocs/content/en/reference/components-reference/supported-state-stores/setup-azure-cosmosdb.md b/daprdocs/content/en/reference/components-reference/supported-state-stores/setup-azure-cosmosdb.md index a69ad8b7f..3b4965deb 100644 --- a/daprdocs/content/en/reference/components-reference/supported-state-stores/setup-azure-cosmosdb.md +++ b/daprdocs/content/en/reference/components-reference/supported-state-stores/setup-azure-cosmosdb.md @@ -70,7 +70,7 @@ Azure Cosmos DB shares a strict metadata request rate limit across all databases Therefore several strategies must be applied to avoid simultaneous new connections to Azure Cosmos DB: -- Ensure sidecars of applications only load the Azure Cosmos DB component when they require it to avoid unnecessary database connections. This can be done by [scoping your components to specific applications]({{< ref component-scopes.md#application-access-to-components-with-scopes >}}). +- Ensure sidecars of applications only load the Azure Cosmos DB component when they require it to avoid unnecessary database connections. This can be done by [scoping your components to specific applications]({{< ref component-scopes.md >}}#application-access-to-components-with-scopes). - Choose deployment strategies that sequentially deploy or start all applications to minimize bursts in new connections to your Azure Cosmos DB accounts. - Avoid reusing the same Azure Cosmos DB account for unrelated databases or systems (even outside of Dapr). Distinct Azure Cosmos DB accounts have distinct rate limits. - Increase the `initTimeout` value to allow the component to retry connecting to Azure Cosmos DB during side car initialization for up to 5 minutes. The default value is `5s` and should be increased. Using Kubernetes increasing this value may also require an update to your [Readiness and Liveness probes](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/). From b53373c10e875aeab33c62af13f5911113c03809 Mon Sep 17 00:00:00 2001 From: Bernd Verst <4535280+berndverst@users.noreply.github.com> Date: Tue, 30 Nov 2021 17:32:02 -0800 Subject: [PATCH 16/30] Grammar change --- .../components-reference/supported-bindings/cosmosdb.md | 2 +- .../supported-state-stores/setup-azure-cosmosdb.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/daprdocs/content/en/reference/components-reference/supported-bindings/cosmosdb.md b/daprdocs/content/en/reference/components-reference/supported-bindings/cosmosdb.md index e35d2ea66..590cb3fc7 100644 --- a/daprdocs/content/en/reference/components-reference/supported-bindings/cosmosdb.md +++ b/daprdocs/content/en/reference/components-reference/supported-bindings/cosmosdb.md @@ -65,7 +65,7 @@ Therefore several strategies must be applied to avoid simultaneous new connectio - Ensure sidecars of applications only load the Azure Cosmos DB component when they require it to avoid unnecessary database connections. This can be done by [scoping your components to specific applications]({{< ref component-scopes.md >}}#application-access-to-components-with-scopes). - Choose deployment strategies that sequentially deploy or start all applications to minimize bursts in new connections to your Azure Cosmos DB accounts. - Avoid reusing the same Azure Cosmos DB account for unrelated databases or systems (even outside of Dapr). Distinct Azure Cosmos DB accounts have distinct rate limits. -- Increase the `initTimeout` value to allow the component to retry connecting to Azure Cosmos DB during side car initialization for up to 5 minutes. The default value is `5s` and should be increased. Using Kubernetes increasing this value may also require an update to your [Readiness and Liveness probes](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/). +- Increase the `initTimeout` value to allow the component to retry connecting to Azure Cosmos DB during side car initialization for up to 5 minutes. The default value is `5s` and should be increased. When using Kubernetes, increasing this value may also require an update to your [Readiness and Liveness probes](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/). ```yaml spec: diff --git a/daprdocs/content/en/reference/components-reference/supported-state-stores/setup-azure-cosmosdb.md b/daprdocs/content/en/reference/components-reference/supported-state-stores/setup-azure-cosmosdb.md index 3b4965deb..5656383b9 100644 --- a/daprdocs/content/en/reference/components-reference/supported-state-stores/setup-azure-cosmosdb.md +++ b/daprdocs/content/en/reference/components-reference/supported-state-stores/setup-azure-cosmosdb.md @@ -73,7 +73,7 @@ Therefore several strategies must be applied to avoid simultaneous new connectio - Ensure sidecars of applications only load the Azure Cosmos DB component when they require it to avoid unnecessary database connections. This can be done by [scoping your components to specific applications]({{< ref component-scopes.md >}}#application-access-to-components-with-scopes). - Choose deployment strategies that sequentially deploy or start all applications to minimize bursts in new connections to your Azure Cosmos DB accounts. - Avoid reusing the same Azure Cosmos DB account for unrelated databases or systems (even outside of Dapr). Distinct Azure Cosmos DB accounts have distinct rate limits. -- Increase the `initTimeout` value to allow the component to retry connecting to Azure Cosmos DB during side car initialization for up to 5 minutes. The default value is `5s` and should be increased. Using Kubernetes increasing this value may also require an update to your [Readiness and Liveness probes](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/). +- Increase the `initTimeout` value to allow the component to retry connecting to Azure Cosmos DB during side car initialization for up to 5 minutes. The default value is `5s` and should be increased. When using Kubernetes, increasing this value may also require an update to your [Readiness and Liveness probes](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/). ## Data format From 873bcb27c18978c87f34ffd9461313c500af9e6c Mon Sep 17 00:00:00 2001 From: Bernd Verst <4535280+berndverst@users.noreply.github.com> Date: Tue, 30 Nov 2021 17:40:45 -0800 Subject: [PATCH 17/30] minor wording --- .../components-reference/supported-bindings/cosmosdb.md | 2 +- .../supported-state-stores/setup-azure-cosmosdb.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/daprdocs/content/en/reference/components-reference/supported-bindings/cosmosdb.md b/daprdocs/content/en/reference/components-reference/supported-bindings/cosmosdb.md index 590cb3fc7..57d71e8b9 100644 --- a/daprdocs/content/en/reference/components-reference/supported-bindings/cosmosdb.md +++ b/daprdocs/content/en/reference/components-reference/supported-bindings/cosmosdb.md @@ -63,7 +63,7 @@ Azure Cosmos DB shares a strict metadata request rate limit across all databases Therefore several strategies must be applied to avoid simultaneous new connections to Azure Cosmos DB: - Ensure sidecars of applications only load the Azure Cosmos DB component when they require it to avoid unnecessary database connections. This can be done by [scoping your components to specific applications]({{< ref component-scopes.md >}}#application-access-to-components-with-scopes). -- Choose deployment strategies that sequentially deploy or start all applications to minimize bursts in new connections to your Azure Cosmos DB accounts. +- Choose deployment strategies that sequentially deploy or start your applications to minimize bursts in new connections to your Azure Cosmos DB accounts. - Avoid reusing the same Azure Cosmos DB account for unrelated databases or systems (even outside of Dapr). Distinct Azure Cosmos DB accounts have distinct rate limits. - Increase the `initTimeout` value to allow the component to retry connecting to Azure Cosmos DB during side car initialization for up to 5 minutes. The default value is `5s` and should be increased. When using Kubernetes, increasing this value may also require an update to your [Readiness and Liveness probes](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/). diff --git a/daprdocs/content/en/reference/components-reference/supported-state-stores/setup-azure-cosmosdb.md b/daprdocs/content/en/reference/components-reference/supported-state-stores/setup-azure-cosmosdb.md index 5656383b9..de940ef02 100644 --- a/daprdocs/content/en/reference/components-reference/supported-state-stores/setup-azure-cosmosdb.md +++ b/daprdocs/content/en/reference/components-reference/supported-state-stores/setup-azure-cosmosdb.md @@ -71,7 +71,7 @@ Azure Cosmos DB shares a strict metadata request rate limit across all databases Therefore several strategies must be applied to avoid simultaneous new connections to Azure Cosmos DB: - Ensure sidecars of applications only load the Azure Cosmos DB component when they require it to avoid unnecessary database connections. This can be done by [scoping your components to specific applications]({{< ref component-scopes.md >}}#application-access-to-components-with-scopes). -- Choose deployment strategies that sequentially deploy or start all applications to minimize bursts in new connections to your Azure Cosmos DB accounts. +- Choose deployment strategies that sequentially deploy or start your applications to minimize bursts in new connections to your Azure Cosmos DB accounts. - Avoid reusing the same Azure Cosmos DB account for unrelated databases or systems (even outside of Dapr). Distinct Azure Cosmos DB accounts have distinct rate limits. - Increase the `initTimeout` value to allow the component to retry connecting to Azure Cosmos DB during side car initialization for up to 5 minutes. The default value is `5s` and should be increased. When using Kubernetes, increasing this value may also require an update to your [Readiness and Liveness probes](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/). From ea8d9ef06f61e238c5951222f8531c54d324ce79 Mon Sep 17 00:00:00 2001 From: Bernd Verst <4535280+berndverst@users.noreply.github.com> Date: Tue, 30 Nov 2021 17:44:59 -0800 Subject: [PATCH 18/30] Add initTimeout example for cosmosdb state --- .../supported-state-stores/setup-azure-cosmosdb.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/daprdocs/content/en/reference/components-reference/supported-state-stores/setup-azure-cosmosdb.md b/daprdocs/content/en/reference/components-reference/supported-state-stores/setup-azure-cosmosdb.md index de940ef02..f1d3c3450 100644 --- a/daprdocs/content/en/reference/components-reference/supported-state-stores/setup-azure-cosmosdb.md +++ b/daprdocs/content/en/reference/components-reference/supported-state-stores/setup-azure-cosmosdb.md @@ -75,6 +75,14 @@ Therefore several strategies must be applied to avoid simultaneous new connectio - Avoid reusing the same Azure Cosmos DB account for unrelated databases or systems (even outside of Dapr). Distinct Azure Cosmos DB accounts have distinct rate limits. - Increase the `initTimeout` value to allow the component to retry connecting to Azure Cosmos DB during side car initialization for up to 5 minutes. The default value is `5s` and should be increased. When using Kubernetes, increasing this value may also require an update to your [Readiness and Liveness probes](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/). +```yaml +spec: + type: state.azure.cosmosdb + version: v1 + initTimeout: 5m + metadata: +``` + ## Data format To use the CosmosDB state store, your data must be sent to Dapr in JSON-serialized. Having it just JSON *serializable* will not work. From 0ea7939195169bec188b98b46c1ecaddc8e3341b Mon Sep 17 00:00:00 2001 From: greenie-msft <56556602+greenie-msft@users.noreply.github.com> Date: Tue, 30 Nov 2021 18:06:30 -0800 Subject: [PATCH 19/30] Update howto-invoke-discover-services.md --- .../service-invocation/howto-invoke-discover-services.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/daprdocs/content/en/developing-applications/building-blocks/service-invocation/howto-invoke-discover-services.md b/daprdocs/content/en/developing-applications/building-blocks/service-invocation/howto-invoke-discover-services.md index d7ec89069..f0110e05b 100644 --- a/daprdocs/content/en/developing-applications/building-blocks/service-invocation/howto-invoke-discover-services.md +++ b/daprdocs/content/en/developing-applications/building-blocks/service-invocation/howto-invoke-discover-services.md @@ -10,7 +10,7 @@ This article describe how to deploy services each with an unique application ID, ## Example: -The below code examples loosely describe an application that processes orders. In the examples, there are two services - an order processing service and a checkout service. Both services have Dapr sidecars and the order processing service uses Dapr to invoke the checkout method in the checkout service. +The below code examples loosely describes an application that processes orders. In the examples, there are two services - an order processing service and a checkout service. Both services have Dapr sidecars and the order processing service uses Dapr to invoke the checkout method in the checkout service. Diagram showing service invocation of example service @@ -363,4 +363,4 @@ For more information on tracing and logs see the [observability]({{< ref observa ## Related Links * [Service invocation overview]({{< ref service-invocation-overview.md >}}) -* [Service invocation API specification]({{< ref service_invocation_api.md >}}) \ No newline at end of file +* [Service invocation API specification]({{< ref service_invocation_api.md >}}) From 93e096a663e06d2f9aa1fb0d9d7f86e1052ce378 Mon Sep 17 00:00:00 2001 From: Amulya Varote Date: Tue, 30 Nov 2021 19:21:42 -0800 Subject: [PATCH 20/30] Renamed example image files --- ...building-block-state-management-example.png | Bin 0 -> 123199 bytes ...lding_block_service_invocation_example.png} | Bin 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 daprdocs/static/images/building-block-state-management-example.png rename daprdocs/static/images/{service_invocation_eg.png => building_block_service_invocation_example.png} (100%) diff --git a/daprdocs/static/images/building-block-state-management-example.png b/daprdocs/static/images/building-block-state-management-example.png new file mode 100644 index 0000000000000000000000000000000000000000..87b3b9b326111244ffff390df68ff79b0198757c GIT binary patch literal 123199 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

MXw*t7 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 Date: Tue, 30 Nov 2021 19:28:00 -0800 Subject: [PATCH 21/30] Changed image name in the docs --- .../howto-invoke-discover-services.md | 2 +- .../state-management/howto-get-save-state.md | 2 +- ...> building-block-service-invocation-example.png} | Bin 3 files changed, 2 insertions(+), 2 deletions(-) rename daprdocs/static/images/{building_block_service_invocation_example.png => building-block-service-invocation-example.png} (100%) diff --git a/daprdocs/content/en/developing-applications/building-blocks/service-invocation/howto-invoke-discover-services.md b/daprdocs/content/en/developing-applications/building-blocks/service-invocation/howto-invoke-discover-services.md index f0110e05b..4f0cb2127 100644 --- a/daprdocs/content/en/developing-applications/building-blocks/service-invocation/howto-invoke-discover-services.md +++ b/daprdocs/content/en/developing-applications/building-blocks/service-invocation/howto-invoke-discover-services.md @@ -12,7 +12,7 @@ This article describe how to deploy services each with an unique application ID, The below code examples loosely describes an application that processes orders. In the examples, there are two services - an order processing service and a checkout service. Both services have Dapr sidecars and the order processing service uses Dapr to invoke the checkout method in the checkout service. -Diagram showing service invocation of example service +Diagram showing service invocation of example service ## Step 1: Choose an ID for your service diff --git a/daprdocs/content/en/developing-applications/building-blocks/state-management/howto-get-save-state.md b/daprdocs/content/en/developing-applications/building-blocks/state-management/howto-get-save-state.md index 89839db12..1684b7ddb 100644 --- a/daprdocs/content/en/developing-applications/building-blocks/state-management/howto-get-save-state.md +++ b/daprdocs/content/en/developing-applications/building-blocks/state-management/howto-get-save-state.md @@ -23,7 +23,7 @@ In this guide we'll start of with the basics: Using the key/value state API to a The below code examples loosely describe an application that processes orders. In the examples, there is an order processing service which has a Dapr sidecar. The order processing service uses Dapr to store state in a Redis state store. -Diagram showing state management of example service +Diagram showing state management of example service ## Step 1: Setup a state store diff --git a/daprdocs/static/images/building_block_service_invocation_example.png b/daprdocs/static/images/building-block-service-invocation-example.png similarity index 100% rename from daprdocs/static/images/building_block_service_invocation_example.png rename to daprdocs/static/images/building-block-service-invocation-example.png From 5b7b4ff61672805061f0e7c5ee6590e06cec20e9 Mon Sep 17 00:00:00 2001 From: greenie-msft <56556602+greenie-msft@users.noreply.github.com> Date: Tue, 30 Nov 2021 19:44:11 -0800 Subject: [PATCH 22/30] Update state-store-ttl.md (#2016) Co-authored-by: Mark Fussell --- .../building-blocks/state-management/state-store-ttl.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/daprdocs/content/en/developing-applications/building-blocks/state-management/state-store-ttl.md b/daprdocs/content/en/developing-applications/building-blocks/state-management/state-store-ttl.md index 14f0034f0..a87587b15 100644 --- a/daprdocs/content/en/developing-applications/building-blocks/state-management/state-store-ttl.md +++ b/daprdocs/content/en/developing-applications/building-blocks/state-management/state-store-ttl.md @@ -1,7 +1,7 @@ --- type: docs -title: "State Time-to-Live (TTL)" -linkTitle: "State TTL" +title: "How-To: Set state Time-to-Live (TTL)" +linkTitle: "How-To: Set state TTL" weight: 500 description: "Manage state with time-to-live." --- From a645f66b12fe4daaa62191d61c698ffa4b285831 Mon Sep 17 00:00:00 2001 From: Amulya Varote Date: Wed, 1 Dec 2021 11:19:08 -0800 Subject: [PATCH 23/30] Added secrets store documentation --- .../building-blocks/secrets/howto-secrets.md | 271 +++++++++++++----- ...lding-block-secrets-management-example.png | Bin 0 -> 112715 bytes 2 files changed, 192 insertions(+), 79 deletions(-) create mode 100644 daprdocs/static/images/building-block-secrets-management-example.png diff --git a/daprdocs/content/en/developing-applications/building-blocks/secrets/howto-secrets.md b/daprdocs/content/en/developing-applications/building-blocks/secrets/howto-secrets.md index 4ada756ba..cc1c7b313 100644 --- a/daprdocs/content/en/developing-applications/building-blocks/secrets/howto-secrets.md +++ b/daprdocs/content/en/developing-applications/building-blocks/secrets/howto-secrets.md @@ -8,17 +8,23 @@ description: "Use the secret store building block to securely retrieve a secret" This article provides guidance on using Dapr's secrets API in your code to leverage the [secrets store building block]({{}}). The secrets API allows you to easily retrieve secrets in your application code from a configured secret store. +## Example + +The below code examples loosely describe an application that processes orders. In the examples, there is an order processing service which has a Dapr sidecar. The order processing service uses Dapr to store secret in a local secret store. + +Diagram showing secrets management of example service + ## Set up a secret store Before retrieving secrets in your application's code, you must have a secret store component configured. For the purposes of this guide, as an example you will configure a local secret store which uses a local JSON file to store secrets. >Note: The component used in this example is not secured and is not recommended for production deployments. You can find other alternatives [here]({{}}). -Create a file named `mysecrets.json` with the following contents: +Create a file named `secrets.json` with the following contents: ```json { - "my-secret" : "I'm Batman" + "secret": "Order Processing pass key" } ``` @@ -28,146 +34,253 @@ Create a directory for your components file named `components` and inside it cre apiVersion: dapr.io/v1alpha1 kind: Component metadata: - name: my-secrets-store + name: localsecretstore namespace: default spec: type: secretstores.local.file version: v1 metadata: - name: secretsFile - value: /mysecrets.json + value: secrets.json - name: nestedSeparator value: ":" ``` -Make sure to replace `` with the path to the JSON file you just created. - ->Note: the path to the secret store JSON is relative to where you call `dapr run` from. - - To configure a different kind of secret store see the guidance on [how to configure a secret store]({{}}) and review [supported secret stores]({{}}) to see specific details required for different secret store solutions. ## Get a secret Now run the Dapr sidecar (with no application) + +{{< tabs Dotnet Java Python Go Javascript>}} + +{{% codetab %}} ```bash -dapr run --app-id my-app --dapr-http-port 3500 --components-path ./components +dapr run --app-id orderprocessingservice --app-port 6001 --dapr-http-port 3601 --dapr-grpc-port 60001 --components-path ./components dotnet run ``` +{{% /codetab %}} + + +{{% codetab %}} +```bash +dapr run --app-id orderprocessingservice --app-port 6001 --dapr-http-port 3601 --dapr-grpc-port 60001 --components-path ./components mvn spring-boot:run +``` +{{% /codetab %}} + + +{{% codetab %}} +```bash +dapr run --app-id orderprocessingservice --app-port 6001 --dapr-http-port 3601 --dapr-grpc-port 60001 --components-path ./components python3 OrderProcessingService.py +``` +{{% /codetab %}} + + +{{% codetab %}} +```bash +dapr run --app-id orderprocessingservice --app-port 6001 --dapr-http-port 3601 --dapr-grpc-port 60001 --components-path ./components go run OrderProcessingService.go +``` +{{% /codetab %}} + + +{{% codetab %}} +```bash +dapr run --app-id orderprocessingservice --app-port 6001 --dapr-http-port 3601 --dapr-grpc-port 60001 --components-path ./components npm start +``` +{{% /codetab %}} + +{{< /tabs >}} And now you can get the secret by calling the Dapr sidecar using the secrets API: ```bash -curl http://localhost:3500/v1.0/secrets/my-secrets-store/my-secret +curl http://localhost:3601/v1.0/secrets/localsecretstore/secret ``` For a full API reference, go [here]({{< ref secrets_api.md >}}). ## Calling the secrets API from your code -Once you have a secret store set up, you can call Dapr to get the secrets from your application code. Here are a few examples in different programming languages: +Once you have a secret store set up, call Dapr to get the secrets from your application code. Below are code examples that leverage Dapr SDKs for retrieving a secret. -{{< tabs "Go" "Javascript" "Python" "Rust" "C#" "PHP" >}} +{{< tabs Dotnet Java Python Go Javascript>}} {{% codetab %}} -```Go -import ( - "fmt" - "net/http" -) +```csharp -func main() { - url := "http://localhost:3500/v1.0/secrets/my-secrets-store/my-secret" +//dependencies +using System; +using System.Collections.Generic; +using System.Net.Http; +using System.Net.Http.Headers; +using System.Threading.Tasks; +using Dapr.Client; +using Microsoft.AspNetCore.Mvc; +using System.Threading; +using System.Text.Json; - res, err := http.Get(url) - if err != nil { - panic(err) - } - defer res.Body.Close() - - body, _ := ioutil.ReadAll(res.Body) - fmt.Println(string(body)) +//code +namespace EventService +{ + class Program + { + static async Task Main(string[] args) + { + string SECRET_STORE_NAME = "localsecretstore"; + using var client = new DaprClientBuilder().Build(); + //Using Dapr SDK to get a secret + var secret = await client.GetSecretAsync(SECRET_STORE_NAME, "secret"); + Console.WriteLine($"Result: {string.Join(", ", secret)}"); + secret = await client.GetSecretAsync(SECRET_STORE_NAME, "secret"); + Console.WriteLine($"Result for bulk: {string.Join(", ", secret.Keys)}"); + } + } } -``` +``` {{% /codetab %}} {{% codetab %}} -```javascript -require('isomorphic-fetch'); -const secretsUrl = `http://localhost:3500/v1.0/secrets`; +```java + +//dependencies +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import io.dapr.client.DaprClient; +import io.dapr.client.DaprClientBuilder; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.*; + +//code +@SpringBootApplication +public class OrderProcessingServiceApplication { + + private static final Logger log = LoggerFactory.getLogger(OrderProcessingServiceApplication.class); + private static final ObjectMapper JSON_SERIALIZER = new ObjectMapper(); + + private static final String SECRET_STORE_NAME = "localsecretstore"; + + public static void main(String[] args) throws InterruptedException, JsonProcessingException { + DaprClient client = new DaprClientBuilder().build(); + //Using Dapr SDK to get a secret + Map secret = client.getSecret(SECRET_STORE_NAME, "secret").block(); + log.info("Result: " + JSON_SERIALIZER.writeValueAsString(secret)); + try { + secret = client.getSecret(SECRET_STORE_NAME, "secret").block(); + log.info("Result for random key: " + JSON_SERIALIZER.writeValueAsString(secret)); + } catch (Exception ex) { + System.out.println("Got error for accessing key"); + } + } +} -fetch(`${secretsUrl}/my-secrets-store/my-secret`) - .then((response) => { - if (!response.ok) { - throw "Could not get secret"; - } - return response.text(); - }).then((secret) => { - console.log(secret); - }); ``` - {{% /codetab %}} {{% codetab %}} ```python -import requests as req -resp = req.get("http://localhost:3500/v1.0/secrets/my-secrets-store/my-secret") -print(resp.text) +#dependencies +import logging +from dapr.clients import DaprClient +from dapr.clients.grpc._state import StateItem +from dapr.clients.grpc._request import TransactionalStateOperation, TransactionOperationType + +#code +logging.basicConfig(level = logging.INFO) + +DAPR_STORE_NAME = "localsecretstore" +key = 'secret' + +with DaprClient() as client: + #Using Dapr SDK to get a secret + secret = client.get_secret(store_name=DAPR_STORE_NAME, key=key) + logging.info('Result: ') + logging.info(secret.secret) + secret = client.get_bulk_secret(store_name=DAPR_STORE_NAME) + logging.info('Result for bulk secret: ') + logging.info(sorted(secret.secrets.items())) + try: + secret = client.get_secret(store_name=DAPR_STORE_NAME, key=key) + logging.info('Result for random key: ') + logging.info(secret.secret) + except: + print("Got error for accessing key") + ``` - {{% /codetab %}} - {{% codetab %}} -```rust -#![deny(warnings)] -use std::{thread}; +```go -#[tokio::main] -async fn main() -> Result<(), reqwest::Error> { - let res = reqwest::get("http://localhost:3500/v1.0/secrets/my-secrets-store/my-secret").await?; - let body = res.text().await?; - println!("Secret:{}", body); +//dependencies +import ( + "context" + "log" + dapr "github.com/dapr/go-sdk/client" +) - thread::park(); +//code +func main() { + client, err := dapr.NewClient() + SECRET_STORE_NAME := "localsecretstore" + if err != nil { + panic(err) + } + defer client.Close() + ctx := context.Background() - Ok(()) + secret, err := client.GetSecret(ctx, SECRET_STORE_NAME, "secret", nil) + if err != nil { + return nil, errors.Wrap(err, "Got error for accessing key") + } + + if secret != nil { + log.Println("Result : ") + log.Println(secret) + } + + secretRandom, err := client.GetBulkSecret(ctx, SECRET_STORE_NAME, nil) + if err != nil { + return nil, errors.Wrap(err, "Got error for accessing key") + } + + if secret != nil { + log.Println("Result for bulk: ") + log.Println(secretRandom) + } } -``` -{{% /codetab %}} - -{{% codetab %}} - -```csharp -var client = new HttpClient(); -var response = await client.GetAsync("http://localhost:3500/v1.0/secrets/my-secrets-store/my-secret"); -response.EnsureSuccessStatusCode(); - -string secret = await response.Content.ReadAsStringAsync(); -Console.WriteLine(secret); ``` {{% /codetab %}} {{% codetab %}} -```php -run(function(\Dapr\SecretManager $secretManager, \Psr\Log\LoggerInterface $logger) { - $secret = $secretManager->retrieve(secret_store: 'my-secret-store', name: 'my-secret'); - $logger->alert('got secret: {secret}', ['secret' => $secret]); -}); ``` - {{% /codetab %}} {{< /tabs >}} @@ -179,4 +292,4 @@ $app->run(function(\Dapr\SecretManager $secretManager, \Psr\Log\LoggerInterface - [Configure a secret store]({{}}) - [Supported secrets]({{}}) - [Using secrets in components]({{}}) -- [Secret stores quickstart](https://github.com/dapr/quickstarts/tree/master/secretstore) +- [Secret stores quickstart](https://github.com/dapr/quickstarts/tree/master/secretstore) \ No newline at end of file diff --git a/daprdocs/static/images/building-block-secrets-management-example.png b/daprdocs/static/images/building-block-secrets-management-example.png new file mode 100644 index 0000000000000000000000000000000000000000..77c450d810cccdafc04c6a45c01839e20bf0bd4f GIT binary patch literal 112715 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 literal 0 HcmV?d00001 From 22104085f9c6007a65504b5b03e73592b780ea6b Mon Sep 17 00:00:00 2001 From: Amulya Varote Date: Thu, 2 Dec 2021 00:58:46 -0800 Subject: [PATCH 24/30] Modified based on the review comments - 1 --- .../building-blocks/secrets/howto-secrets.md | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/daprdocs/content/en/developing-applications/building-blocks/secrets/howto-secrets.md b/daprdocs/content/en/developing-applications/building-blocks/secrets/howto-secrets.md index cc1c7b313..5ea5f9546 100644 --- a/daprdocs/content/en/developing-applications/building-blocks/secrets/howto-secrets.md +++ b/daprdocs/content/en/developing-applications/building-blocks/secrets/howto-secrets.md @@ -18,7 +18,7 @@ The below code examples loosely describe an application that processes orders. I Before retrieving secrets in your application's code, you must have a secret store component configured. For the purposes of this guide, as an example you will configure a local secret store which uses a local JSON file to store secrets. ->Note: The component used in this example is not secured and is not recommended for production deployments. You can find other alternatives [here]({{}}). +>Note: The component used in this example is not secure and is not recommended for production deployments. You can find other alternatives [here]({{}}). Create a file named `secrets.json` with the following contents: @@ -46,10 +46,12 @@ spec: value: ":" ``` +>Note: the path to the secret store JSON is relative to where you call `dapr run` from. + To configure a different kind of secret store see the guidance on [how to configure a secret store]({{}}) and review [supported secret stores]({{}}) to see specific details required for different secret store solutions. ## Get a secret -Now run the Dapr sidecar (with no application) +Now run the Dapr sidecar with the application. {{< tabs Dotnet Java Python Go Javascript>}} @@ -130,7 +132,6 @@ namespace EventService //Using Dapr SDK to get a secret var secret = await client.GetSecretAsync(SECRET_STORE_NAME, "secret"); Console.WriteLine($"Result: {string.Join(", ", secret)}"); - secret = await client.GetSecretAsync(SECRET_STORE_NAME, "secret"); Console.WriteLine($"Result for bulk: {string.Join(", ", secret.Keys)}"); } } @@ -168,12 +169,6 @@ public class OrderProcessingServiceApplication { //Using Dapr SDK to get a secret Map secret = client.getSecret(SECRET_STORE_NAME, "secret").block(); log.info("Result: " + JSON_SERIALIZER.writeValueAsString(secret)); - try { - secret = client.getSecret(SECRET_STORE_NAME, "secret").block(); - log.info("Result for random key: " + JSON_SERIALIZER.writeValueAsString(secret)); - } catch (Exception ex) { - System.out.println("Got error for accessing key"); - } } } From dde92676b680f32d2700f08fb2e2bf4fced2d5ca Mon Sep 17 00:00:00 2001 From: Amulya Varote Date: Thu, 2 Dec 2021 01:07:23 -0800 Subject: [PATCH 25/30] Modified based on the review comments - 1 --- .../building-blocks/secrets/howto-secrets.md | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/daprdocs/content/en/developing-applications/building-blocks/secrets/howto-secrets.md b/daprdocs/content/en/developing-applications/building-blocks/secrets/howto-secrets.md index 5ea5f9546..61ee0909d 100644 --- a/daprdocs/content/en/developing-applications/building-blocks/secrets/howto-secrets.md +++ b/daprdocs/content/en/developing-applications/building-blocks/secrets/howto-secrets.md @@ -41,7 +41,7 @@ spec: version: v1 metadata: - name: secretsFile - value: secrets.json + value: secrets.json //path to secrets file - name: nestedSeparator value: ":" ``` @@ -199,12 +199,6 @@ with DaprClient() as client: secret = client.get_bulk_secret(store_name=DAPR_STORE_NAME) logging.info('Result for bulk secret: ') logging.info(sorted(secret.secrets.items())) - try: - secret = client.get_secret(store_name=DAPR_STORE_NAME, key=key) - logging.info('Result for random key: ') - logging.info(secret.secret) - except: - print("Got error for accessing key") ``` {{% /codetab %}} From 4f08464dae428a4596f9ff90990c8f6140c04d81 Mon Sep 17 00:00:00 2001 From: Amulya Varote Date: Thu, 2 Dec 2021 01:10:26 -0800 Subject: [PATCH 26/30] Added comment --- .../building-blocks/secrets/howto-secrets.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/daprdocs/content/en/developing-applications/building-blocks/secrets/howto-secrets.md b/daprdocs/content/en/developing-applications/building-blocks/secrets/howto-secrets.md index 61ee0909d..d0c5b07d3 100644 --- a/daprdocs/content/en/developing-applications/building-blocks/secrets/howto-secrets.md +++ b/daprdocs/content/en/developing-applications/building-blocks/secrets/howto-secrets.md @@ -41,7 +41,7 @@ spec: version: v1 metadata: - name: secretsFile - value: secrets.json //path to secrets file + value: secrets.json #path to secrets file - name: nestedSeparator value: ":" ``` From 6506dbf6a74d84f4669edf0da7e31f881adb2f31 Mon Sep 17 00:00:00 2001 From: Amulya Varote Date: Thu, 2 Dec 2021 10:35:59 -0800 Subject: [PATCH 27/30] Modified based on the review comments - 2 --- .../building-blocks/secrets/howto-secrets.md | 26 ++++--------------- 1 file changed, 5 insertions(+), 21 deletions(-) diff --git a/daprdocs/content/en/developing-applications/building-blocks/secrets/howto-secrets.md b/daprdocs/content/en/developing-applications/building-blocks/secrets/howto-secrets.md index d0c5b07d3..88c12195f 100644 --- a/daprdocs/content/en/developing-applications/building-blocks/secrets/howto-secrets.md +++ b/daprdocs/content/en/developing-applications/building-blocks/secrets/howto-secrets.md @@ -10,7 +10,7 @@ This article provides guidance on using Dapr's secrets API in your code to lever ## Example -The below code examples loosely describe an application that processes orders. In the examples, there is an order processing service which has a Dapr sidecar. The order processing service uses Dapr to store secret in a local secret store. +The below code examples loosely describe an application that processes orders. In the examples, there is an order processing service which has a Dapr sidecar. The order processing service uses Dapr to store a secret in a local secret store. Diagram showing secrets management of example service @@ -18,7 +18,7 @@ The below code examples loosely describe an application that processes orders. I Before retrieving secrets in your application's code, you must have a secret store component configured. For the purposes of this guide, as an example you will configure a local secret store which uses a local JSON file to store secrets. ->Note: The component used in this example is not secure and is not recommended for production deployments. You can find other alternatives [here]({{}}). +>Note: In a production-grade application, local secret stores are not recommended. You can find other alternatives [here]({{}}) to securely manage your secrets. Create a file named `secrets.json` with the following contents: @@ -51,7 +51,7 @@ spec: To configure a different kind of secret store see the guidance on [how to configure a secret store]({{}}) and review [supported secret stores]({{}}) to see specific details required for different secret store solutions. ## Get a secret -Now run the Dapr sidecar with the application. +Run the Dapr sidecar with the application. {{< tabs Dotnet Java Python Go Javascript>}} @@ -92,7 +92,7 @@ dapr run --app-id orderprocessingservice --app-port 6001 --dapr-http-port 3601 - {{< /tabs >}} -And now you can get the secret by calling the Dapr sidecar using the secrets API: +Get the secret by calling the Dapr sidecar using the secrets API: ```bash curl http://localhost:3601/v1.0/secrets/localsecretstore/secret @@ -102,7 +102,7 @@ For a full API reference, go [here]({{< ref secrets_api.md >}}). ## Calling the secrets API from your code -Once you have a secret store set up, call Dapr to get the secrets from your application code. Below are code examples that leverage Dapr SDKs for retrieving a secret. +Once you have a secret store, call Dapr to get the secrets from your application code. Below are code examples that leverage Dapr SDKs for retrieving a secret. {{< tabs Dotnet Java Python Go Javascript>}} @@ -110,15 +110,7 @@ Once you have a secret store set up, call Dapr to get the secrets from your appl ```csharp //dependencies -using System; -using System.Collections.Generic; -using System.Net.Http; -using System.Net.Http.Headers; -using System.Threading.Tasks; using Dapr.Client; -using Microsoft.AspNetCore.Mvc; -using System.Threading; -using System.Text.Json; //code namespace EventService @@ -145,15 +137,8 @@ namespace EventService ```java //dependencies -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; import io.dapr.client.DaprClient; import io.dapr.client.DaprClientBuilder; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.*; //code @SpringBootApplication @@ -180,7 +165,6 @@ public class OrderProcessingServiceApplication { ```python #dependencies -import logging from dapr.clients import DaprClient from dapr.clients.grpc._state import StateItem from dapr.clients.grpc._request import TransactionalStateOperation, TransactionOperationType From 0b29c8fb3b7e4304b3438cec49c235ae3fdbcb62 Mon Sep 17 00:00:00 2001 From: greenie-msft <56556602+greenie-msft@users.noreply.github.com> Date: Thu, 2 Dec 2021 13:39:46 -0800 Subject: [PATCH 28/30] Update daprdocs/content/en/developing-applications/building-blocks/secrets/howto-secrets.md --- .../building-blocks/secrets/howto-secrets.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/daprdocs/content/en/developing-applications/building-blocks/secrets/howto-secrets.md b/daprdocs/content/en/developing-applications/building-blocks/secrets/howto-secrets.md index 88c12195f..058837b4a 100644 --- a/daprdocs/content/en/developing-applications/building-blocks/secrets/howto-secrets.md +++ b/daprdocs/content/en/developing-applications/building-blocks/secrets/howto-secrets.md @@ -10,7 +10,7 @@ This article provides guidance on using Dapr's secrets API in your code to lever ## Example -The below code examples loosely describe an application that processes orders. In the examples, there is an order processing service which has a Dapr sidecar. The order processing service uses Dapr to store a secret in a local secret store. +The below code examples loosely describes an application that processes orders. In the examples, there is an order processing service which has a Dapr sidecar. The order processing service uses Dapr to store a secret in a local secret store. Diagram showing secrets management of example service From 3488c63a92886c383f5a19b3ec74b09feed66d2a Mon Sep 17 00:00:00 2001 From: greenie-msft <56556602+greenie-msft@users.noreply.github.com> Date: Thu, 2 Dec 2021 13:41:40 -0800 Subject: [PATCH 29/30] Update daprdocs/content/en/developing-applications/building-blocks/secrets/howto-secrets.md --- .../building-blocks/secrets/howto-secrets.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/daprdocs/content/en/developing-applications/building-blocks/secrets/howto-secrets.md b/daprdocs/content/en/developing-applications/building-blocks/secrets/howto-secrets.md index 058837b4a..3ecb2c9a3 100644 --- a/daprdocs/content/en/developing-applications/building-blocks/secrets/howto-secrets.md +++ b/daprdocs/content/en/developing-applications/building-blocks/secrets/howto-secrets.md @@ -10,7 +10,7 @@ This article provides guidance on using Dapr's secrets API in your code to lever ## Example -The below code examples loosely describes an application that processes orders. In the examples, there is an order processing service which has a Dapr sidecar. The order processing service uses Dapr to store a secret in a local secret store. +The below code example loosely describes an application that processes orders. In the example, there is an order processing service, which has a Dapr sidecar. The order processing service uses Dapr to store a secret in a local secret store. Diagram showing secrets management of example service From 3f66120d6325a5e058780dbf531a974cde57de5e Mon Sep 17 00:00:00 2001 From: greenie-msft <56556602+greenie-msft@users.noreply.github.com> Date: Thu, 2 Dec 2021 13:43:12 -0800 Subject: [PATCH 30/30] Update daprdocs/content/en/developing-applications/building-blocks/secrets/howto-secrets.md --- .../building-blocks/secrets/howto-secrets.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/daprdocs/content/en/developing-applications/building-blocks/secrets/howto-secrets.md b/daprdocs/content/en/developing-applications/building-blocks/secrets/howto-secrets.md index 3ecb2c9a3..73565e055 100644 --- a/daprdocs/content/en/developing-applications/building-blocks/secrets/howto-secrets.md +++ b/daprdocs/content/en/developing-applications/building-blocks/secrets/howto-secrets.md @@ -18,7 +18,9 @@ The below code example loosely describes an application that processes orders. I Before retrieving secrets in your application's code, you must have a secret store component configured. For the purposes of this guide, as an example you will configure a local secret store which uses a local JSON file to store secrets. ->Note: In a production-grade application, local secret stores are not recommended. You can find other alternatives [here]({{}}) to securely manage your secrets. +{{% alert title="Warning" color="warning" %}} +In a production-grade application, local secret stores are not recommended. You can find other alternatives [here]({{}}) to securely manage your secrets. +{{% /alert %}} Create a file named `secrets.json` with the following contents: