From 8901c9d6fe0d6559be1b0657ca751d8487f92fee Mon Sep 17 00:00:00 2001 From: Amulya Varote Date: Tue, 23 Nov 2021 02:52:27 -0800 Subject: [PATCH 1/9] State Management documentation --- .../howto-invoke-discover-services.md | 12 +- .../state-management/howto-get-save-state.md | 920 ++++++++++-------- 2 files changed, 547 insertions(+), 385 deletions(-) diff --git a/daprdocs/content/en/developing-applications/building-blocks/service-invocation/howto-invoke-discover-services.md b/daprdocs/content/en/developing-applications/building-blocks/service-invocation/howto-invoke-discover-services.md index 6e99d4a04..185d718ab 100644 --- a/daprdocs/content/en/developing-applications/building-blocks/service-invocation/howto-invoke-discover-services.md +++ b/daprdocs/content/en/developing-applications/building-blocks/service-invocation/howto-invoke-discover-services.md @@ -184,7 +184,7 @@ Below are code examples that leverage Dapr SDKs for service invocation. {{% codetab %}} ```csharp -//headers +//dependencies using Dapr.Client; using System.Net.Http; @@ -204,7 +204,7 @@ await client.InvokeMethodAsync(result); {{% codetab %}} ```java -//headers +//dependencies import io.dapr.client.DaprClient; import io.dapr.client.DaprClientBuilder; @@ -227,11 +227,11 @@ var result = daprClient.invokeMethod( {{% codetab %}} ```python -//headers +#dependencies from dapr.clients import DaprClient -//code +#code with DaprClient() as daprClient: result = daprClient.invoke_method( @@ -247,7 +247,7 @@ with DaprClient() as daprClient: {{% codetab %}} ```go -//headers +//dependencies import ( dapr "github.com/dapr/go-sdk/client" ) @@ -269,7 +269,7 @@ result, err := client.InvokeMethod(ctx, "checkout", "checkout/" + strconv.Itoa(o {{% codetab %}} ```javascript -//headers +//dependencies import { DaprClient, HttpMethod, CommunicationProtocolEnum } from 'dapr-client'; diff --git a/daprdocs/content/en/developing-applications/building-blocks/state-management/howto-get-save-state.md b/daprdocs/content/en/developing-applications/building-blocks/state-management/howto-get-save-state.md index d00c1ea61..e3a678037 100644 --- a/daprdocs/content/en/developing-applications/building-blocks/state-management/howto-get-save-state.md +++ b/daprdocs/content/en/developing-applications/building-blocks/state-management/howto-get-save-state.md @@ -19,6 +19,12 @@ In this guide we'll start of with the basics: Using the key/value state API to a - [Dapr CLI]({{< ref install-dapr-cli.md >}}) - Initialized [Dapr environment]({{< ref install-dapr-selfhost.md >}}) +## Example: + +The below code examples loosely describe an application that processes orders. In the examples, there is one service - an order processing service. This service has Dapr sidecar and the order processing service uses Dapr to store state in redis state store. + +Diagram showing state management of example service + ## Step 1: Setup a state store A state store component represents a resource that Dapr uses to communicate with a database. @@ -66,130 +72,210 @@ The following example shows how to a single key/value pair using the Dapr state It is important to set an app-id, as the state keys are prefixed with this value. If you don't set it one is generated for you at runtime, and the next time you run the command a new one will be generated and you will no longer be able to access previously saved state. {{% /alert %}} -{{< tabs "HTTP API (Bash)" "HTTP API (PowerShell)" "Python SDK" "PHP SDK">}} +Below are code examples that leverage Dapr SDKs for saving and retrieving a single state. -{{% codetab %}} -Begin by launching a Dapr sidecar: - -```bash -dapr run --app-id myapp --dapr-http-port 3500 -``` - -Then in a separate terminal save a key/value pair into your statestore: -```bash -curl -X POST -H "Content-Type: application/json" -d '[{ "key": "key1", "value": "value1"}]' http://localhost:3500/v1.0/state/statestore -``` - -Now get the state you just saved: -```bash -curl http://localhost:3500/v1.0/state/statestore/key1 -``` - -You can also restart your sidecar and try retrieving state again to see that state persists separate from the app. -{{% /codetab %}} +{{< tabs Dotnet Java Python Go Javascript "HTTP API (Bash)" "HTTP API (PowerShell)">}} {{% codetab %}} -Begin by launching a Dapr sidecar: +```csharp +//dependencies + +using Dapr.Client; + +//code + +string DAPR_STORE_NAME = "statestore"; + +using var client = new DaprClientBuilder().Build(); +await client.SaveStateAsync(DAPR_STORE_NAME, "order_1", orderId.ToString()); +var result = await client.GetStateAsync(DAPR_STORE_NAME, orderId.ToString()); +Console.WriteLine("Result after get: " + result); + +``` + +Once saved run the following command to launch a Dapr sidecar and run the application: ```bash -dapr --app-id myapp --port 3500 run +dapr run --app-id orderprocessing --app-port 6001 --dapr-http-port 3601 --dapr-grpc-port 60001 dotnet run ``` -Then in a separate terminal save a key/value pair into your statestore: -```powershell -Invoke-RestMethod -Method Post -ContentType 'application/json' -Body '[{"key": "key1", "value": "value1"}]' -Uri 'http://localhost:3500/v1.0/state/statestore' -``` - -Now get the state you just saved: -```powershell -Invoke-RestMethod -Uri 'http://localhost:3500/v1.0/state/statestore/key1' -``` - -You can also restart your sidecar and try retrieving state again to see that state persists separate from the app. - {{% /codetab %}} + + {{% codetab %}} -Save the following to a file named `pythonState.py`: +```java +//dependencies + +import io.dapr.client.DaprClient; +import io.dapr.client.DaprClientBuilder; + +//code + +private static final String STATE_STORE_NAME = "statestore"; + +DaprClient client = new DaprClientBuilder().build(); +client.saveState(STATE_STORE_NAME, "order_1", Integer.toString(orderId)).block(); +Mono> result = client.getState(STATE_STORE_NAME, "order_1", String.class); +log.info("Result after get" + result); + +``` + +Once saved run the following command to launch a Dapr sidecar and run the application: + +```bash +dapr run --app-id orderprocessing --app-port 6001 --dapr-http-port 3601 --dapr-grpc-port 60001 mvn spring-boot:run +``` + +{{% /codetab %}} + + +{{% codetab %}} ```python +#dependencies + from dapr.clients import DaprClient -with DaprClient() as d: - d.save_state(store_name="statestore", key="myFirstKey", value="myFirstValue" ) - print("State has been stored") +#code - data = d.get_state(store_name="statestore", key="myFirstKey").data - print(f"Got value: {data}") +DAPR_STORE_NAME = "statestore" + +with DaprClient() as client: + client.save_state(DAPR_STORE_NAME, "order_1", str(orderId)) + result = client.get_state(DAPR_STORE_NAME, "order_1") + logging.info('Result after get: ' + str(result)) ``` -Once saved run the following command to launch a Dapr sidecar and run the Python application: +Once saved run the following command to launch a Dapr sidecar and run the application: ```bash -dapr --app-id myapp run python pythonState.py -``` - -You should get an output similar to the following, which will show both the Dapr and app logs: - -```md -== DAPR == time="2021-01-06T21:34:33.7970377-08:00" level=info msg="starting Dapr Runtime -- version 0.11.3 -- commit a1a8e11" app_id=Braidbald-Boot scope=dapr.runtime type=log ver=0.11.3 -== DAPR == time="2021-01-06T21:34:33.8040378-08:00" level=info msg="standalone mode configured" app_id=Braidbald-Boot scope=dapr.runtime type=log ver=0.11.3 -== DAPR == time="2021-01-06T21:34:33.8040378-08:00" level=info msg="app id: Braidbald-Boot" app_id=Braidbald-Boot scope=dapr.runtime type=log ver=0.11.3 -== DAPR == time="2021-01-06T21:34:33.9750400-08:00" level=info msg="component loaded. name: statestore, type: state.redis" app_id=Braidbald-Boot scope=dapr.runtime type=log ver=0.11.3 -== DAPR == time="2021-01-06T21:34:33.9760387-08:00" level=info msg="API gRPC server is running on port 51656" app_id=Braidbald-Boot scope=dapr.runtime type=log ver=0.11.3 -== DAPR == time="2021-01-06T21:34:33.9770372-08:00" level=info msg="dapr initialized. Status: Running. Init Elapsed 172.9994ms" app_id=Braidbald-Boot scope=dapr. - -Checking if Dapr sidecar is listening on GRPC port 51656 -Dapr sidecar is up and running. -Updating metadata for app command: python pythonState.py -You are up and running! Both Dapr and your app logs will appear here. - -== APP == State has been stored -== APP == Got value: b'myFirstValue' +dapr run --app-id orderprocessing --app-port 6001 --dapr-http-port 3601 --dapr-grpc-port 60001 -- python3 OrderProcessingService.py ``` {{% /codetab %}} + {{% codetab %}} -Save the following in `state-example.php`: +```go +//dependencies -```php -run(function(\Dapr\State\StateManager $stateManager, \Psr\Log\LoggerInterface $logger) { - $stateManager->save_state(store_name: 'statestore', item: new \Dapr\State\StateItem( - key: 'myFirstKey', - value: 'myFirstValue' - )); - $logger->alert('State has been stored'); - $data = $stateManager->load_state(store_name: 'statestore', key: 'myFirstKey')->value; - $logger->alert("Got value: {data}", ['data' => $data]); -}); ``` -Once saved run the following command to launch a Dapr sidecar and run the PHP application: +Once saved run the following command to launch a Dapr sidecar and run the application: ```bash -dapr --app-id myapp run -- php state-example.php +dapr run --app-id orderprocessing --app-port 6001 --dapr-http-port 3601 --dapr-grpc-port 60001 go run OrderProcessingService.go ``` -You should get an output similar to the following, which will show both the Dapr and app logs: +{{% /codetab %}} -```md -✅ You're up and running! Both Dapr and your app logs will appear here. -== APP == [2021-02-12T16:30:11.078777+01:00] APP.ALERT: State has been stored [] [] +{{% codetab %}} + +```javascript +//dependencies + +import { DaprClient, HttpMethod, CommunicationProtocolEnum } from 'dapr-client'; + +//code + +const STATE_STORE_NAME = "statestore"; + +const daprHost = "127.0.0.1"; +const client = new DaprClient(daprHost, process.env.DAPR_HTTP_PORT, CommunicationProtocolEnum.HTTP); +await client.state.save(STATE_STORE_NAME, [ +{ + key: "order_1", + value: orderId.toString() +}]); +var result = await client.state.get(STATE_STORE_NAME, "order_1"); +console.log("Result after get: " + result); + -== APP == [2021-02-12T16:30:11.082620+01:00] APP.ALERT: Got value: myFirstValue {"data":"myFirstValue"} [] ``` +Once saved run the following command to launch a Dapr sidecar and run the application: + +```bash +dapr run --app-id orderprocessing --app-port 6001 --dapr-http-port 3601 --dapr-grpc-port 60001 npm start +``` + +{{% /codetab %}} + + +{{% codetab %}} +Begin by launching a Dapr sidecar: + +```bash +dapr run --app-id orderprocessing --dapr-http-port 3601 +``` + +Then in a separate terminal save a key/value pair into your statestore: +```bash +curl -X POST -H "Content-Type: application/json" -d '[{ "key": "order_1", "value": "250"}]' http://localhost:3601/v1.0/state/statestore +``` + +Now get the state you just saved: +```bash +curl http://localhost:3601/v1.0/state/statestore/order_1 +``` + +You can also restart your sidecar and try retrieving state again to see that state persists separate from the app. +{{% /codetab %}} + +{{% codetab %}} + +Begin by launching a Dapr sidecar: + +```bash +dapr --app-id orderprocessing --port 3601 run +``` + +Then in a separate terminal save a key/value pair into your statestore: +```powershell +Invoke-RestMethod -Method Post -ContentType 'application/json' -Body '[{"key": "order_1", "value": "250"}]' -Uri 'http://localhost:3601/v1.0/state/statestore' +``` + +Now get the state you just saved: +```powershell +Invoke-RestMethod -Uri 'http://localhost:3601/v1.0/state/statestore/order_1' +``` + +You can also restart your sidecar and try retrieving state again to see that state persists separate from the app. + {{% /codetab %}} {{< /tabs >}} @@ -197,14 +283,150 @@ You should get an output similar to the following, which will show both the Dapr ## Step 3: Delete state -The following example shows how to delete an item by using a key with the state management API: +Below are code examples that leverage Dapr SDKs for deleting the state. -{{< tabs "HTTP API (Bash)" "HTTP API (PowerShell)" "Python SDK" "PHP SDK">}} +{{< tabs Dotnet Java Python Go Javascript "HTTP API (Bash)" "HTTP API (PowerShell)">}} + +{{% codetab %}} + +```csharp +//dependencies + +using Dapr.Client; + +//code + +string DAPR_STORE_NAME = "statestore"; + +await client.DeleteStateAsync(DAPR_STORE_NAME, "order_1", cancellationToken: cancellationToken); + +``` + +Once saved run the following command to launch a Dapr sidecar and run the application: + +```bash +dapr run --app-id orderprocessing --app-port 6001 --dapr-http-port 3601 --dapr-grpc-port 60001 dotnet run +``` + +{{% /codetab %}} + + +{{% codetab %}} + +```java +//dependencies + +import io.dapr.client.DaprClient; +import io.dapr.client.DaprClientBuilder; + +//code + +private static final String STATE_STORE_NAME = "statestore"; + +DaprClient client = new DaprClientBuilder().build(); +String storedEtag = client.getState(STATE_STORE_NAME, "order_1", String.class).block().getEtag(); +client.deleteState(STATE_STORE_NAME, "order_1", storedEtag, null).block(); + +``` + +Once saved run the following command to launch a Dapr sidecar and run the application: + +```bash +dapr run --app-id orderprocessing --app-port 6001 --dapr-http-port 3601 --dapr-grpc-port 60001 mvn spring-boot:run +``` + +{{% /codetab %}} + + +{{% codetab %}} + +```python +#dependencies + +from dapr.clients import DaprClient + +#code + +DAPR_STORE_NAME = "statestore" + +with DaprClient() as client: + client.delete_state(store_name=DAPR_STORE_NAME, key="order_1") + +``` + +Once saved run the following command to launch a Dapr sidecar and run the application: + +```bash +dapr run --app-id orderprocessing --app-port 6001 --dapr-http-port 3601 --dapr-grpc-port 60001 -- python3 OrderProcessingService.py +``` + +{{% /codetab %}} + + +{{% codetab %}} + +```go +//dependencies + +import ( + dapr "github.com/dapr/go-sdk/client" +) + +//code + +client, err := dapr.NewClient() +STATE_STORE_NAME := "statestore" + +if err != nil { + panic(err) +} +defer client.Close() +ctx := context.Background() + +if err := client.DeleteState(ctx, store, "order_1"); err != nil { + panic(err) +} + +``` + +Once saved run the following command to launch a Dapr sidecar and run the application: + +```bash +dapr run --app-id orderprocessing --app-port 6001 --dapr-http-port 3601 --dapr-grpc-port 60001 go run OrderProcessingService.go +``` + +{{% /codetab %}} + + +{{% codetab %}} + +```javascript +//dependencies + +import { DaprClient, HttpMethod, CommunicationProtocolEnum } from 'dapr-client'; + +//code + +const STATE_STORE_NAME = "statestore"; + +const client = new DaprClient(daprHost, process.env.DAPR_HTTP_PORT, CommunicationProtocolEnum.HTTP); +await client.state.delete(STATE_STORE_NAME, "order_1"); + + +``` + +Once saved run the following command to launch a Dapr sidecar and run the application: + +```bash +dapr run --app-id orderprocessing --app-port 6001 --dapr-http-port 3601 --dapr-grpc-port 60001 npm start +``` + +{{% /codetab %}} {{% codetab %}} With the same dapr instance running from above run: ```bash -curl -X DELETE 'http://localhost:3500/v1.0/state/statestore/key1' +curl -X DELETE 'http://localhost:3601/v1.0/state/statestore/order_1' ``` Try getting state again and note that no value is returned. {{% /codetab %}} @@ -212,228 +434,134 @@ Try getting state again and note that no value is returned. {{% codetab %}} With the same dapr instance running from above run: ```powershell -Invoke-RestMethod -Method Delete -Uri 'http://localhost:3500/v1.0/state/statestore/key1' +Invoke-RestMethod -Method Delete -Uri 'http://localhost:3601/v1.0/state/statestore/order_1' ``` Try getting state again and note that no value is returned. {{% /codetab %}} -{{% codetab %}} - -Update `pythonState.py` with: - -```python -from dapr.clients import DaprClient - -with DaprClient() as d: - d.save_state(store_name="statestore", key="key1", value="value1" ) - print("State has been stored") - - data = d.get_state(store_name="statestore", key="key1").data - print(f"Got value: {data}") - - d.delete_state(store_name="statestore", key="key1") - - data = d.get_state(store_name="statestore", key="key1").data - print(f"Got value after delete: {data}") -``` - -Now run your program with: - -```bash -dapr --app-id myapp run python pythonState.py -``` - -You should see an output similar to the following: - -```md -Starting Dapr with id Yakchocolate-Lord. HTTP Port: 59457. gRPC Port: 59458 - -== DAPR == time="2021-01-06T22:55:36.5570696-08:00" level=info msg="starting Dapr Runtime -- version 0.11.3 -- commit a1a8e11" app_id=Yakchocolate-Lord scope=dapr.runtime type=log ver=0.11.3 -== DAPR == time="2021-01-06T22:55:36.5690367-08:00" level=info msg="standalone mode configured" app_id=Yakchocolate-Lord scope=dapr.runtime type=log ver=0.11.3 -== DAPR == time="2021-01-06T22:55:36.7220140-08:00" level=info msg="component loaded. name: statestore, type: state.redis" app_id=Yakchocolate-Lord scope=dapr.runtime type=log ver=0.11.3 -== DAPR == time="2021-01-06T22:55:36.7230148-08:00" level=info msg="API gRPC server is running on port 59458" app_id=Yakchocolate-Lord scope=dapr.runtime type=log ver=0.11.3 -== DAPR == time="2021-01-06T22:55:36.7240207-08:00" level=info msg="dapr initialized. Status: Running. Init Elapsed 154.984ms" app_id=Yakchocolate-Lord scope=dapr.runtime type=log ver=0.11.3 - -Checking if Dapr sidecar is listening on GRPC port 59458 -Dapr sidecar is up and running. -Updating metadata for app command: python pythonState.py -You're up and running! Both Dapr and your app logs will appear here. - -== APP == State has been stored -== APP == Got value: b'value1' -== APP == Got value after delete: b'' -``` -{{% /codetab %}} - -{{% codetab %}} - -Update `state-example.php` with the following contents: - -```php -run(function(\Dapr\State\StateManager $stateManager, \Psr\Log\LoggerInterface $logger) { - $stateManager->save_state(store_name: 'statestore', item: new \Dapr\State\StateItem( - key: 'myFirstKey', - value: 'myFirstValue' - )); - $logger->alert('State has been stored'); - - $data = $stateManager->load_state(store_name: 'statestore', key: 'myFirstKey')->value; - $logger->alert("Got value: {data}", ['data' => $data]); - - $stateManager->delete_keys(store_name: 'statestore', keys: ['myFirstKey']); - $data = $stateManager->load_state(store_name: 'statestore', key: 'myFirstKey')->value; - $logger->alert("Got value after delete: {data}", ['data' => $data]); -}); -``` - -Now run it with: - -```bash -dapr --app-id myapp run -- php state-example.php -``` - -You should see something similar the following output: - -```md -✅ You're up and running! Both Dapr and your app logs will appear here. - -== APP == [2021-02-12T16:38:00.839201+01:00] APP.ALERT: State has been stored [] [] - -== APP == [2021-02-12T16:38:00.841997+01:00] APP.ALERT: Got value: myFirstValue {"data":"myFirstValue"} [] - -== APP == [2021-02-12T16:38:00.845721+01:00] APP.ALERT: Got value after delete: {"data":null} [] -``` - -{{% /codetab %}} - {{< /tabs >}} ## Step 4: Save and retrieve multiple states -Dapr also allows you to save and retrieve multiple states in the same call. +Below are code examples that leverage Dapr SDKs for saving and retrieving multiple states. -{{< tabs "HTTP API (Bash)" "HTTP API (PowerShell)" "Python SDK" "PHP SDK">}} +{{< tabs Java Python Javascript "HTTP API (Bash)" "HTTP API (PowerShell)">}} {{% codetab %}} -With the same dapr instance running from above save two key/value pairs into your statestore: + +```java +//dependencies + +import io.dapr.client.DaprClient; +import io.dapr.client.DaprClientBuilder; +import reactor.core.publisher.Mono; +import io.dapr.client.domain.State; +import java.util.List; + +//code + +private static final String STATE_STORE_NAME = "statestore"; + +DaprClient client = new DaprClientBuilder().build(); +Mono>> resultBulk = client.getBulkState(STATE_STORE_NAME, + Arrays.asList("order_1", "order_2"), String.class); +log.info("Result after get bulk" + resultBulk); + +``` + +Once saved run the following command to launch a Dapr sidecar and run the application: + ```bash -curl -X POST -H "Content-Type: application/json" -d '[{ "key": "key1", "value": "value1"}, { "key": "key2", "value": "value2"}]' http://localhost:3500/v1.0/state/statestore -``` - -Now get the states you just saved: -```bash -curl -X POST -H "Content-Type: application/json" -d '{"keys":["key1", "key2"]}' http://localhost:3500/v1.0/state/statestore/bulk -``` -{{% /codetab %}} - -{{% codetab %}} -With the same dapr instance running from above save two key/value pairs into your statestore: -```powershell -Invoke-RestMethod -Method Post -ContentType 'application/json' -Body '[{ "key": "key1", "value": "value1"}, { "key": "key2", "value": "value2"}]' -Uri 'http://localhost:3500/v1.0/state/statestore' -``` - -Now get the states you just saved: -```powershell -Invoke-RestMethod -Method Post -ContentType 'application/json' -Body '{"keys":["key1", "key2"]}' -Uri 'http://localhost:3500/v1.0/state/statestore/bulk' +dapr run --app-id orderprocessing --app-port 6001 --dapr-http-port 3601 --dapr-grpc-port 60001 mvn spring-boot:run ``` {{% /codetab %}} + {{% codetab %}} -The `StateItem` object can be used to store multiple Dapr states with the `save_states` and `get_states` methods. - -Update your `pythonState.py` file with the following code: - ```python +#dependencies + from dapr.clients import DaprClient from dapr.clients.grpc._state import StateItem -with DaprClient() as d: - s1 = StateItem(key="key1", value="value1") - s2 = StateItem(key="key2", value="value2") +#code - d.save_bulk_state(store_name="statestore", states=[s1,s2]) - print("States have been stored") +DAPR_STORE_NAME = "statestore" + +with DaprClient() as client: + client.save_bulk_state(store_name=DAPR_STORE_NAME, states=[StateItem(key="order_2", value=str(orderId))]) + result = client.get_bulk_state(store_name=DAPR_STORE_NAME, keys=["order_1", "order_2"], states_metadata={"metakey": "metavalue"}).items + logging.info('Result after get bulk: ' + str(result)) - items = d.get_bulk_state(store_name="statestore", keys=["key1", "key2"]).items - print(f"Got items: {[i.data for i in items]}") ``` -Now run your program with: +Once saved run the following command to launch a Dapr sidecar and run the application: ```bash -dapr --app-id myapp run python pythonState.py +dapr run --app-id orderprocessing --app-port 6001 --dapr-http-port 3601 --dapr-grpc-port 60001 -- python3 OrderProcessingService.py ``` -You should see an output similar to the following: +{{% /codetab %}} -```md -== DAPR == time="2021-01-06T21:54:56.7262358-08:00" level=info msg="starting Dapr Runtime -- version 0.11.3 -- commit a1a8e11" app_id=Musesequoia-Sprite scope=dapr.runtime type=log ver=0.11.3 -== DAPR == time="2021-01-06T21:54:56.7401933-08:00" level=info msg="standalone mode configured" app_id=Musesequoia-Sprite scope=dapr.runtime type=log ver=0.11.3 -== DAPR == time="2021-01-06T21:54:56.8754240-08:00" level=info msg="Initialized name resolution to standalone" app_id=Musesequoia-Sprite scope=dapr.runtime type=log ver=0.11.3 -== DAPR == time="2021-01-06T21:54:56.8844248-08:00" level=info msg="component loaded. name: statestore, type: state.redis" app_id=Musesequoia-Sprite scope=dapr.runtime type=log ver=0.11.3 -== DAPR == time="2021-01-06T21:54:56.8854273-08:00" level=info msg="API gRPC server is running on port 60614" app_id=Musesequoia-Sprite scope=dapr.runtime type=log ver=0.11.3 -== DAPR == time="2021-01-06T21:54:56.8854273-08:00" level=info msg="dapr initialized. Status: Running. Init Elapsed 145.234ms" app_id=Musesequoia-Sprite scope=dapr.runtime type=log ver=0.11.3 -Checking if Dapr sidecar is listening on GRPC port 60614 -Dapr sidecar is up and running. -Updating metadata for app command: python pythonState.py -You're up and running! Both Dapr and your app logs will appear here. -== APP == States have been stored -== APP == Got items: [b'value1', b'value2'] +{{% codetab %}} + +```javascript +//dependencies + +import { DaprClient, HttpMethod, CommunicationProtocolEnum } from 'dapr-client'; + +//code + +const client = new DaprClient(daprHost, process.env.DAPR_HTTP_PORT, CommunicationProtocolEnum.HTTP); +const STATE_STORE_NAME = "statestore"; +await client.state.save(STATE_STORE_NAME, [ + { + key: "order_1", + value: orderId.toString() + }, + { + key: "order_2", + value: orderId.toString() + } +]); +result = await client.state.getBulk(STATE_STORE_NAME, ["order_1", "order_2"]); +console.log("Result after get bulk: " + result); + +``` + +Once saved run the following command to launch a Dapr sidecar and run the application: + +```bash +dapr run --app-id orderprocessing --app-port 6001 --dapr-http-port 3601 --dapr-grpc-port 60001 npm start ``` {{% /codetab %}} {{% codetab %}} - -To batch load and save state with PHP, just create a "Plain Ole' PHP Object" (POPO) and annotate it with -the StateStore annotation. - -Update the `state-example.php` file: - -```php -run(function(\Dapr\State\StateManager $stateManager, \Psr\Log\LoggerInterface $logger) { - $obj = new MyState(); - $stateManager->save_object(item: $obj); - $logger->alert('States have been stored'); - - $stateManager->load_object(into: $obj); - $logger->alert("Got value: {data}", ['data' => $obj]); -}); -``` - -Run the app: - +With the same dapr instance running from above save two key/value pairs into your statestore: ```bash -dapr --app-id myapp run -- php state-example.php +curl -X POST -H "Content-Type: application/json" -d '[{ "key": "order_1", "value": "250"}, { "key": "order_2", "value": "550"}]' http://localhost:3601/v1.0/state/statestore ``` -And see the following output: +Now get the states you just saved: +```bash +curl -X POST -H "Content-Type: application/json" -d '{"keys":["order_1", "order_2"]}' http://localhost:3601/v1.0/state/statestore/bulk +``` +{{% /codetab %}} -```md -✅ You're up and running! Both Dapr and your app logs will appear here. +{{% codetab %}} +With the same dapr instance running from above save two key/value pairs into your statestore: +```powershell +Invoke-RestMethod -Method Post -ContentType 'application/json' -Body '[{ "key": "order_1", "value": "250"}, { "key": "order_2", "value": "550"}]' -Uri 'http://localhost:3601/v1.0/state/statestore' +``` -== APP == [2021-02-12T16:55:02.913801+01:00] APP.ALERT: States have been stored [] [] - -== APP == [2021-02-12T16:55:02.917850+01:00] APP.ALERT: Got value: [object MyState] {"data":{"MyState":{"key1":"value1","key2":"value2"}}} [] +Now get the states you just saved: +```powershell +Invoke-RestMethod -Method Post -ContentType 'application/json' -Body '{"keys":["order_1", "order_2"]}' -Uri 'http://localhost:3601/v1.0/state/statestore/bulk' ``` {{% /codetab %}} @@ -446,138 +574,172 @@ And see the following output: State transactions require a state store that supports multi-item transactions. Visit the [supported state stores page]({{< ref supported-state-stores >}}) page for a full list. Note that the default Redis container created in a self-hosted environment supports them. {{% /alert %}} -{{< tabs "HTTP API (Bash)" "HTTP API (PowerShell)" "Python SDK" "PHP SDK">}} +Below are code examples that leverage Dapr SDKs for performing state transactions. + +{{< tabs Dotnet Java Python Javascript "HTTP API (Bash)" "HTTP API (PowerShell)">}} + +{{% codetab %}} + +```csharp +//dependencies + +using Dapr.Client; + +//code + +string DAPR_STORE_NAME = "statestore"; +using var client = new DaprClientBuilder().Build(); +var requests = new List() +{ + new StateTransactionRequest("order_3", JsonSerializer.SerializeToUtf8Bytes(orderId.ToString()), StateOperationType.Upsert), + new StateTransactionRequest("order_2", null, StateOperationType.Delete) +}; + +CancellationTokenSource source = new CancellationTokenSource(); +CancellationToken cancellationToken = source.Token; + +await client.ExecuteStateTransactionAsync(DAPR_STORE_NAME, requests, cancellationToken: cancellationToken); + +``` + +Once saved run the following command to launch a Dapr sidecar and run the application: + +```bash +dapr run --app-id orderprocessing --app-port 6001 --dapr-http-port 3601 --dapr-grpc-port 60001 dotnet run +``` + +{{% /codetab %}} + + +{{% codetab %}} + +```java +//dependencies + +import io.dapr.client.DaprClient; +import io.dapr.client.DaprClientBuilder; +import io.dapr.client.domain.State; +import io.dapr.client.domain.TransactionalStateOperation; + +//code + +private static final String STATE_STORE_NAME = "statestore"; + +DaprClient client = new DaprClientBuilder().build(); +List> operationList = new ArrayList<>(); +operationList.add(new TransactionalStateOperation<>(TransactionalStateOperation.OperationType.UPSERT, + new State<>("order_3", Integer.toString(orderId), ""))); +operationList.add(new TransactionalStateOperation<>(TransactionalStateOperation.OperationType.DELETE, + new State<>("order_2"))); +client.executeStateTransaction(STATE_STORE_NAME, operationList).block(); + +``` + +Once saved run the following command to launch a Dapr sidecar and run the application: + +```bash +dapr run --app-id orderprocessing --app-port 6001 --dapr-http-port 3601 --dapr-grpc-port 60001 mvn spring-boot:run +``` + +{{% /codetab %}} + + +{{% codetab %}} + +```python +#dependencies + +from dapr.clients import DaprClient +from dapr.clients.grpc._state import StateItem +from dapr.clients.grpc._request import TransactionalStateOperation, TransactionOperationType + +#code + +DAPR_STORE_NAME = "statestore" +with DaprClient() as client: + client.execute_state_transaction(store_name=DAPR_STORE_NAME, operations=[ + TransactionalStateOperation( + operation_type=TransactionOperationType.upsert, + key="order_3", + data=str(orderId)), + TransactionalStateOperation(key="order_3", data=str(orderId)), + TransactionalStateOperation( + operation_type=TransactionOperationType.delete, + key="order_2", + data=str(orderId)), + TransactionalStateOperation(key="order_2", data=str(orderId)) + ]) + +``` + +Once saved run the following command to launch a Dapr sidecar and run the application: + +```bash +dapr run --app-id orderprocessing --app-port 6001 --dapr-http-port 3601 --dapr-grpc-port 60001 -- python3 OrderProcessingService.py +``` + +{{% /codetab %}} + + +{{% codetab %}} + +```javascript +//dependencies + +import { DaprClient, HttpMethod, CommunicationProtocolEnum } from 'dapr-client'; + + +//code + +const STATE_STORE_NAME = "statestore"; +const client = new DaprClient(daprHost, process.env.DAPR_HTTP_PORT, CommunicationProtocolEnum.HTTP); +await client.state.transaction(STATE_STORE_NAME, [ + { + operation: "upsert", + request: { + key: "order_3", + value: orderId.toString() + } + }, + { + operation: "delete", + request: { + key: "order_2" + } + } +]); + +``` + +Once saved run the following command to launch a Dapr sidecar and run the application: + +```bash +dapr run --app-id orderprocessing --app-port 6001 --dapr-http-port 3601 --dapr-grpc-port 60001 npm start +``` + +{{% /codetab %}} {{% codetab %}} With the same dapr instance running from above perform two state transactions: ```bash -curl -X POST -H "Content-Type: application/json" -d '{"operations": [{"operation":"upsert", "request": {"key": "key1", "value": "newValue1"}}, {"operation":"delete", "request": {"key": "key2"}}]}' http://localhost:3500/v1.0/state/statestore/transaction +curl -X POST -H "Content-Type: application/json" -d '{"operations": [{"operation":"upsert", "request": {"key": "order_1", "value": "250"}}, {"operation":"delete", "request": {"key": "order_2"}}]}' http://localhost:3601/v1.0/state/statestore/transaction ``` Now see the results of your state transactions: ```bash -curl -X POST -H "Content-Type: application/json" -d '{"keys":["key1", "key2"]}' http://localhost:3500/v1.0/state/statestore/bulk +curl -X POST -H "Content-Type: application/json" -d '{"keys":["order_1", "order_2"]}' http://localhost:3601/v1.0/state/statestore/bulk ``` {{% /codetab %}} {{% codetab %}} With the same dapr instance running from above save two key/value pairs into your statestore: ```powershell -Invoke-RestMethod -Method Post -ContentType 'application/json' -Body '{"operations": [{"operation":"upsert", "request": {"key": "key1", "value": "newValue1"}}, {"operation":"delete", "request": {"key": "key2"}}]}' -Uri 'http://localhost:3500/v1.0/state/statestore' +Invoke-RestMethod -Method Post -ContentType 'application/json' -Body '{"operations": [{"operation":"upsert", "request": {"key": "order_1", "value": "250"}}, {"operation":"delete", "request": {"key": "order_2"}}]}' -Uri 'http://localhost:3601/v1.0/state/statestore' ``` Now see the results of your state transactions: ```powershell -Invoke-RestMethod -Method Post -ContentType 'application/json' -Body '{"keys":["key1", "key2"]}' -Uri 'http://localhost:3500/v1.0/state/statestore/bulk' -``` - -{{% /codetab %}} - -{{% codetab %}} - -The `TransactionalStateOperation` can perform a state transaction if your state stores need to be transactional. - -Update your `pythonState.py` file with the following code: - -```python -from dapr.clients import DaprClient -from dapr.clients.grpc._state import StateItem -from dapr.clients.grpc._request import TransactionalStateOperation, TransactionOperationType - -with DaprClient() as d: - s1 = StateItem(key="key1", value="value1") - s2 = StateItem(key="key2", value="value2") - - d.save_bulk_state(store_name="statestore", states=[s1,s2]) - print("States have been stored") - - d.execute_state_transaction( - store_name="statestore", - operations=[ - TransactionalStateOperation(key="key1", data="newValue1", operation_type=TransactionOperationType.upsert), - TransactionalStateOperation(key="key2", data="value2", operation_type=TransactionOperationType.delete) - ] - ) - print("State transactions have been completed") - - items = d.get_bulk_state(store_name="statestore", keys=["key1", "key2"]).items - print(f"Got items: {[i.data for i in items]}") -``` - -Now run your program with: - -```bash -dapr run python pythonState.py -``` - -You should see an output similar to the following: - -```md -Starting Dapr with id Singerchecker-Player. HTTP Port: 59533. gRPC Port: 59534 -== DAPR == time="2021-01-06T22:18:14.1246721-08:00" level=info msg="starting Dapr Runtime -- version 0.11.3 -- commit a1a8e11" app_id=Singerchecker-Player scope=dapr.runtime type=log ver=0.11.3 -== DAPR == time="2021-01-06T22:18:14.1346254-08:00" level=info msg="standalone mode configured" app_id=Singerchecker-Player scope=dapr.runtime type=log ver=0.11.3 -== DAPR == time="2021-01-06T22:18:14.2747063-08:00" level=info msg="component loaded. name: statestore, type: state.redis" app_id=Singerchecker-Player scope=dapr.runtime type=log ver=0.11.3 -== DAPR == time="2021-01-06T22:18:14.2757062-08:00" level=info msg="API gRPC server is running on port 59534" app_id=Singerchecker-Player scope=dapr.runtime type=log ver=0.11.3 -== DAPR == time="2021-01-06T22:18:14.2767059-08:00" level=info msg="dapr initialized. Status: Running. Init Elapsed 142.0805ms" app_id=Singerchecker-Player scope=dapr.runtime type=log ver=0.11.3 - -Checking if Dapr sidecar is listening on GRPC port 59534 -Dapr sidecar is up and running. -Updating metadata for app command: python pythonState.py -You're up and running! Both Dapr and your app logs will appear here. - -== APP == State transactions have been completed -== APP == Got items: [b'value1', b''] -``` - -{{% /codetab %}} - -{{% codetab %}} - -Transactional state is supported by extending `TransactionalState` base object which hooks into your -object via setters and getters to provide a transaction. Before you created your own transactional object, -but now you'll ask the Dependency Injection framework to build one for you. - -Modify the `state-example.php` file again: - -```php -run(function(MyState $obj, \Psr\Log\LoggerInterface $logger, \Dapr\State\StateManager $stateManager) { - $obj->begin(); - $obj->key1 = 'hello world'; - $obj->key2 = 'value3'; - $obj->commit(); - $logger->alert('Transaction committed!'); - - // begin a new transaction which reloads from the store - $obj->begin(); - $logger->alert("Got value: {key1}, {key2}", ['key1' => $obj->key1, 'key2' => $obj->key2]); -}); -``` - -Run the application: - -```bash -dapr --app-id myapp run -- php state-example.php -``` - -Observe the following output: - -```md -✅ You're up and running! Both Dapr and your app logs will appear here. - -== APP == [2021-02-12T17:10:06.837110+01:00] APP.ALERT: Transaction committed! [] [] - -== APP == [2021-02-12T17:10:06.840857+01:00] APP.ALERT: Got value: hello world, value3 {"key1":"hello world","key2":"value3"} [] +Invoke-RestMethod -Method Post -ContentType 'application/json' -Body '{"keys":["order_1", "order_2"]}' -Uri 'http://localhost:3601/v1.0/state/statestore/bulk' ``` {{% /codetab %}} @@ -588,4 +750,4 @@ Observe the following output: - Read the full [State API reference]({{< ref state_api.md >}}) - Try one of the [Dapr SDKs]({{< ref sdks >}}) -- Build a [stateful service]({{< ref howto-stateful-service.md >}}) +- Build a [stateful service]({{< ref howto-stateful-service.md >}}) \ No newline at end of file From ad20a76b321feff8d43ef6cf26553a78c381330e Mon Sep 17 00:00:00 2001 From: Amulya Varote Date: Tue, 23 Nov 2021 03:09:03 -0800 Subject: [PATCH 2/9] 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 3/9] 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 4/9] Modification based on the review comment - 1 --- .../building-blocks/state-management/howto-get-save-state.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/daprdocs/content/en/developing-applications/building-blocks/state-management/howto-get-save-state.md b/daprdocs/content/en/developing-applications/building-blocks/state-management/howto-get-save-state.md index e096b8c18..ab784b559 100644 --- a/daprdocs/content/en/developing-applications/building-blocks/state-management/howto-get-save-state.md +++ b/daprdocs/content/en/developing-applications/building-blocks/state-management/howto-get-save-state.md @@ -21,7 +21,7 @@ In this guide we'll start of with the basics: Using the key/value state API to a ## Example: -The below code examples loosely describe an application that processes orders. In the examples, there is one service - an order processing service. This service has Dapr sidecar and the order processing service uses Dapr to store state in redis state store. +The below code examples loosely describe an application that processes orders. In the examples, there is an order processing service which has a Dapr sidecar. The order processing service uses Dapr to store state in a Redis state store. Diagram showing state management of example service From 10853723253f65fa87e44ef0ecf21d7ddcf3f27e Mon Sep 17 00:00:00 2001 From: Amulya Varote Date: Wed, 24 Nov 2021 07:21:07 -0800 Subject: [PATCH 5/9] 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 bdba7a680063296481cee81d9babde0eeb3d0e7c Mon Sep 17 00:00:00 2001 From: Amulya Varote Date: Mon, 29 Nov 2021 12:39:52 -0800 Subject: [PATCH 6/9] 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 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 7/9] Update howto-invoke-discover-services.md --- .../service-invocation/howto-invoke-discover-services.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/daprdocs/content/en/developing-applications/building-blocks/service-invocation/howto-invoke-discover-services.md b/daprdocs/content/en/developing-applications/building-blocks/service-invocation/howto-invoke-discover-services.md index d7ec89069..f0110e05b 100644 --- a/daprdocs/content/en/developing-applications/building-blocks/service-invocation/howto-invoke-discover-services.md +++ b/daprdocs/content/en/developing-applications/building-blocks/service-invocation/howto-invoke-discover-services.md @@ -10,7 +10,7 @@ This article describe how to deploy services each with an unique application ID, ## Example: -The below code examples loosely describe an application that processes orders. In the examples, there are two services - an order processing service and a checkout service. Both services have Dapr sidecars and the order processing service uses Dapr to invoke the checkout method in the checkout service. +The below code examples loosely describes an application that processes orders. In the examples, there are two services - an order processing service and a checkout service. Both services have Dapr sidecars and the order processing service uses Dapr to invoke the checkout method in the checkout service. Diagram showing service invocation of example service @@ -363,4 +363,4 @@ For more information on tracing and logs see the [observability]({{< ref observa ## Related Links * [Service invocation overview]({{< ref service-invocation-overview.md >}}) -* [Service invocation API specification]({{< ref service_invocation_api.md >}}) \ No newline at end of file +* [Service invocation API specification]({{< ref service_invocation_api.md >}}) From 93e096a663e06d2f9aa1fb0d9d7f86e1052ce378 Mon Sep 17 00:00:00 2001 From: Amulya Varote Date: Tue, 30 Nov 2021 19:21:42 -0800 Subject: [PATCH 8/9] Renamed example image files --- ...building-block-state-management-example.png | Bin 0 -> 123199 bytes ...lding_block_service_invocation_example.png} | Bin 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 daprdocs/static/images/building-block-state-management-example.png rename daprdocs/static/images/{service_invocation_eg.png => building_block_service_invocation_example.png} (100%) diff --git a/daprdocs/static/images/building-block-state-management-example.png b/daprdocs/static/images/building-block-state-management-example.png new file mode 100644 index 0000000000000000000000000000000000000000..87b3b9b326111244ffff390df68ff79b0198757c GIT binary patch literal 123199 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

MXw*t7 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 Date: Tue, 30 Nov 2021 19:28:00 -0800 Subject: [PATCH 9/9] Changed image name in the docs --- .../howto-invoke-discover-services.md | 2 +- .../state-management/howto-get-save-state.md | 2 +- ...> building-block-service-invocation-example.png} | Bin 3 files changed, 2 insertions(+), 2 deletions(-) rename daprdocs/static/images/{building_block_service_invocation_example.png => building-block-service-invocation-example.png} (100%) diff --git a/daprdocs/content/en/developing-applications/building-blocks/service-invocation/howto-invoke-discover-services.md b/daprdocs/content/en/developing-applications/building-blocks/service-invocation/howto-invoke-discover-services.md index f0110e05b..4f0cb2127 100644 --- a/daprdocs/content/en/developing-applications/building-blocks/service-invocation/howto-invoke-discover-services.md +++ b/daprdocs/content/en/developing-applications/building-blocks/service-invocation/howto-invoke-discover-services.md @@ -12,7 +12,7 @@ This article describe how to deploy services each with an unique application ID, The below code examples loosely describes an application that processes orders. In the examples, there are two services - an order processing service and a checkout service. Both services have Dapr sidecars and the order processing service uses Dapr to invoke the checkout method in the checkout service. -Diagram showing service invocation of example service +Diagram showing service invocation of example service ## Step 1: Choose an ID for your service diff --git a/daprdocs/content/en/developing-applications/building-blocks/state-management/howto-get-save-state.md b/daprdocs/content/en/developing-applications/building-blocks/state-management/howto-get-save-state.md index 89839db12..1684b7ddb 100644 --- a/daprdocs/content/en/developing-applications/building-blocks/state-management/howto-get-save-state.md +++ b/daprdocs/content/en/developing-applications/building-blocks/state-management/howto-get-save-state.md @@ -23,7 +23,7 @@ In this guide we'll start of with the basics: Using the key/value state API to a The below code examples loosely describe an application that processes orders. In the examples, there is an order processing service which has a Dapr sidecar. The order processing service uses Dapr to store state in a Redis state store. -Diagram showing state management of example service +Diagram showing state management of example service ## Step 1: Setup a state store diff --git a/daprdocs/static/images/building_block_service_invocation_example.png b/daprdocs/static/images/building-block-service-invocation-example.png similarity index 100% rename from daprdocs/static/images/building_block_service_invocation_example.png rename to daprdocs/static/images/building-block-service-invocation-example.png