From 49cb7f64ce182bbd2ef8057c205acb79f6ed7e9a Mon Sep 17 00:00:00 2001
From: tanvigour <>
Date: Thu, 18 Nov 2021 16:49:56 +0530
Subject: [PATCH 01/20] 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/20] 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.
+
+
+
## 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/20] 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/20] 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 b1e0921761eac297dea07bceb88b818a156a60bb Mon Sep 17 00:00:00 2001
From: Amulya Varote
Date: Wed, 24 Nov 2021 07:14:06 -0800
Subject: [PATCH 05/20] 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.
From 10853723253f65fa87e44ef0ecf21d7ddcf3f27e Mon Sep 17 00:00:00 2001
From: Amulya Varote
Date: Wed, 24 Nov 2021 07:21:07 -0800
Subject: [PATCH 06/20] 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 2367621c8529abcc6b13c086fcbcf136ec9f7954 Mon Sep 17 00:00:00 2001
From: greenie-msft <56556602+greenie-msft@users.noreply.github.com>
Date: Wed, 24 Nov 2021 15:41:43 -0800
Subject: [PATCH 07/20] Update setup-nats-streaming.md
---
.../supported-pubsub/setup-nats-streaming.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
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 3f307294574d07dee3af4e52342d049c089a4806 Mon Sep 17 00:00:00 2001
From: Massimo Crippa
Date: Fri, 26 Nov 2021 16:43:45 +0100
Subject: [PATCH 08/20] 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 09/20] 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 10/20] 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 11/20] 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 12/20] 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 13/20] 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 14/20] 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 15/20] 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 16/20] 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 17/20] 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.
]
@@ -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 18/20] 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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