Merge pull request #2331 from hhunter-ms/state_stores

Remove list of state stores & link to spec
This commit is contained in:
greenie-msft 2022-04-06 15:45:45 -07:00 committed by GitHub
commit 4c24145035
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 155 additions and 156 deletions

View File

@ -8,7 +8,7 @@ weight: 200
## Component file ## Component file
A Dapr State Store component yaml file has the following structure: A Dapr `statestore.yaml` component file has the following structure:
```yaml ```yaml
apiVersion: dapr.io/v1alpha1 apiVersion: dapr.io/v1alpha1
@ -26,13 +26,10 @@ spec:
value: <VALUE> value: <VALUE>
``` ```
The ```metadata.name``` is the name of the state store. | Setting | Description |
| ------- | ----------- |
the ```spec/metadata``` section is an open key value pair metadata that allows a binding to define connection properties. | `metadata.name` | The name of the state store. |
| `spec/metadata` | An open key value pair metadata that allows a binding to define connection properties. |
Starting with 0.4.0 release, support for multiple state stores was added. This is a breaking change from previous releases as the state APIs were changed to support this new scenario.
Please refer https://github.com/dapr/dapr/blob/master/docs/decision_records/api/API-008-multi-state-store-api-design.md for more details.
## Key scheme ## Key scheme
@ -62,10 +59,10 @@ POST http://localhost:<daprPort>/v1.0/state/<storename>
Parameter | Description Parameter | Description
--------- | ----------- --------- | -----------
daprPort | the Dapr port `daprPort` | The Dapr port
storename | ```metadata.name``` field in the user configured state store component yaml. Please refer Dapr State Store configuration structure mentioned above. `storename` | The `metadata.name` field in the user-configured `statestore.yaml` component file. Refer to the [Dapr state store configuration structure](#component-file) mentioned above.
> Note, all URL parameters are case-sensitive. > All URL parameters are case-sensitive.
#### Request Body #### Request Body
@ -73,13 +70,13 @@ A JSON array of state objects. Each state object is comprised with the following
Field | Description Field | Description
---- | ----------- ---- | -----------
key | state key `key` | State key
value | state value, which can be any byte array `value` | State value, which can be any byte array
etag | (optional) state ETag `etag` | (optional) State ETag
metadata | (optional) additional key-value pairs to be passed to the state store `metadata` | (optional) Additional key-value pairs to be passed to the state store
options | (optional) state operation options, see [state operation options](#optional-behaviors) `options` | (optional) State operation options; see [state operation options](#optional-behaviors)
> **ETag format** Dapr runtime treats ETags as opaque strings. The exact ETag format is defined by the corresponding data store. > **ETag format:** Dapr runtime treats ETags as opaque strings. The exact ETag format is defined by the corresponding data store.
### HTTP Response ### HTTP Response
@ -87,9 +84,9 @@ options | (optional) state operation options, see [state operation options](#opt
Code | Description Code | Description
---- | ----------- ---- | -----------
204 | State saved `204` | State saved
400 | State store is missing or misconfigured or malformed request `400` | State store is missing or misconfigured or malformed request
500 | Failed to save state `500` | Failed to save state
#### Response Body #### Response Body
@ -129,11 +126,11 @@ GET http://localhost:<daprPort>/v1.0/state/<storename>/<key>
Parameter | Description Parameter | Description
--------- | ----------- --------- | -----------
daprPort | the Dapr port `daprPort` | The Dapr port
storename | ```metadata.name``` field in the user configured state store component yaml. Please refer Dapr State Store configuration structure mentioned above. `storename` | `metadata.name` field in the user-configured statestore.yaml component file. Refer to the [Dapr state store configuration structure](#component-file) mentioned above.
key | the key of the desired state `key` | The key of the desired state
consistency | (optional) read consistency mode, see [state operation options](#optional-behaviors) `consistency` | (optional) Read consistency mode; see [state operation options](#optional-behaviors)
metadata | (optional) metadata as query parameters to the state store `metadata` | (optional) Metadata as query parameters to the state store
> Note, all URL parameters are case-sensitive. > Note, all URL parameters are case-sensitive.
@ -143,18 +140,19 @@ metadata | (optional) metadata as query parameters to the state store
Code | Description Code | Description
---- | ----------- ---- | -----------
200 | Get state successful `200` | Get state successful
204 | Key is not found `204` | Key is not found
400 | State store is missing or misconfigured `400` | State store is missing or misconfigured
500 | Get state failed `500` | Get state failed
#### Response Headers #### Response Headers
Header | Description Header | Description
--------- | ----------- --------- | -----------
ETag | ETag of returned value `ETag` | ETag of returned value
#### Response Body #### Response Body
JSON-encoded value JSON-encoded value
### Example ### Example
@ -172,7 +170,7 @@ curl http://localhost:3500/v1.0/state/starwars/planet \
} }
``` ```
To pass metadata as query parammeter: To pass metadata as query parameter:
``` ```
GET http://localhost:3500/v1.0/state/starwars/planet?metadata.partitionKey=mypartitionKey GET http://localhost:3500/v1.0/state/starwars/planet?metadata.partitionKey=mypartitionKey
@ -192,9 +190,9 @@ POST/PUT http://localhost:<daprPort>/v1.0/state/<storename>/bulk
Parameter | Description Parameter | Description
--------- | ----------- --------- | -----------
daprPort | the Dapr port `daprPort` | The Dapr port
storename | ```metadata.name``` field in the user configured state store component yaml. Please refer Dapr State Store configuration structure mentioned above. `storename` | `metadata.name` field in the user-configured statestore.yaml component file. Refer to the [Dapr state store configuration structure](#component-file) mentioned above.
metadata | (optional) metadata as query parameters to the state store `metadata` | (optional) Metadata as query parameters to the state store
> Note, all URL parameters are case-sensitive. > Note, all URL parameters are case-sensitive.
@ -204,11 +202,12 @@ metadata | (optional) metadata as query parameters to the state store
Code | Description Code | Description
---- | ----------- ---- | -----------
200 | Get state successful `200` | Get state successful
400 | State store is missing or misconfigured `400` | State store is missing or misconfigured
500 | Get bulk state failed `500` | Get bulk state failed
#### Response Body #### Response Body
An array of JSON-encoded values An array of JSON-encoded values
### Example ### Example
@ -238,13 +237,13 @@ curl http://localhost:3500/v1.0/state/myRedisStore/bulk \
} }
] ]
``` ```
To pass metadata as query parammeter:
To pass metadata as query parameter:
``` ```
POST http://localhost:3500/v1.0/state/myRedisStore/bulk?metadata.partitionKey=mypartitionKey POST http://localhost:3500/v1.0/state/myRedisStore/bulk?metadata.partitionKey=mypartitionKey
``` ```
## Delete state ## Delete state
This endpoint lets you delete the state for a specific key. This endpoint lets you delete the state for a specific key.
@ -259,11 +258,11 @@ DELETE http://localhost:<daprPort>/v1.0/state/<storename>/<key>
Parameter | Description Parameter | Description
--------- | ----------- --------- | -----------
daprPort | the Dapr port `daprPort` | The Dapr port
storename | ```metadata.name``` field in the user configured state store component yaml. Please refer Dapr State Store configuration structure mentioned above. `storename` | `metadata.name` field in the user-configured statestore.yaml component file. Refer to the [Dapr state store configuration structure](#component-file) mentioned above.
key | the key of the desired state `key` | The key of the desired state
concurrency | (optional) either *first-write* or *last-write*, see [state operation options](#optional-behaviors) `concurrency` | (optional) Either *first-write* or *last-write*; see [state operation options](#optional-behaviors)
consistency | (optional) either *strong* or *eventual*, see [state operation options](#optional-behaviors) `consistency` | (optional) Either *strong* or *eventual*; see [state operation options](#optional-behaviors)
> Note, all URL parameters are case-sensitive. > Note, all URL parameters are case-sensitive.
@ -279,11 +278,12 @@ If-Match | (Optional) ETag associated with the key to be deleted
Code | Description Code | Description
---- | ----------- ---- | -----------
204 | Delete state successful `204` | Delete state successful
400 | State store is missing or misconfigured `400` | State store is missing or misconfigured
500 | Delete state failed `500` | Delete state failed
#### Response Body #### Response Body
None. None.
### Example ### Example
@ -310,9 +310,9 @@ POST/PUT http://localhost:<daprPort>/v1.0-alpha1/state/<storename>/query
Parameter | Description Parameter | Description
--------- | ----------- --------- | -----------
daprPort | the Dapr port `daprPort` | The Dapr port
storename | ```metadata.name``` field in the user configured state store component yaml. Refer to the Dapr state store configuration structure mentioned above. `storename` | `metadata.name` field in the user-configured statestore.yaml component file. Refer to the [Dapr state store configuration structure](#component-file) mentioned above.
metadata | (optional) metadata as query parameters to the state store `metadata` | (optional) Metadata as query parameters to the state store
> Note, all URL parameters are case-sensitive. > Note, all URL parameters are case-sensitive.
@ -320,11 +320,12 @@ metadata | (optional) metadata as query parameters to the state store
Code | Description Code | Description
---- | ----------- ---- | -----------
200 | State query successful `200` | State query successful
400 | State store is missing or misconfigured `400` | State store is missing or misconfigured
500 | State query failed `500` | State query failed
#### Response Body #### Response Body
An array of JSON-encoded values An array of JSON-encoded values
### Example ### Example
@ -410,7 +411,8 @@ curl http://localhost:3500/v1.0-alpha1/state/myStore/query \
"token": "3" "token": "3"
} }
``` ```
To pass metadata as query parammeter:
To pass metadata as query parameter:
``` ```
POST http://localhost:3500/v1.0-alpha1/state/myStore/query?metadata.partitionKey=mypartitionKey POST http://localhost:3500/v1.0-alpha1/state/myStore/query?metadata.partitionKey=mypartitionKey
@ -420,15 +422,9 @@ POST http://localhost:3500/v1.0-alpha1/state/myStore/query?metadata.partitionKey
Persists the changes to the state store as a multi-item transaction. Persists the changes to the state store as a multi-item transaction.
***Note that this operation is dependant on a using state store component that supports multi-item transactions.*** > This operation depends on a state store component that supports multi-item transactions.
List of state stores that support transactions: Refer to the [state store component spec]({{< ref "supported-state-stores.md" >}}) for a full, current list of state stores that support transactions.
* Redis
* MongoDB
* PostgreSQL
* SQL Server
* Azure CosmosDB
#### HTTP Request #### HTTP Request
@ -440,16 +436,16 @@ POST/PUT http://localhost:<daprPort>/v1.0/state/<storename>/transaction
Code | Description Code | Description
---- | ----------- ---- | -----------
204 | Request successful `204` | Request successful
400 | State store is missing or misconfigured or malformed request `400` | State store is missing or misconfigured or malformed request
500 | Request failed `500` | Request failed
#### URL Parameters #### URL Parameters
Parameter | Description Parameter | Description
--------- | ----------- --------- | -----------
daprPort | the Dapr port `daprPort` | The Dapr port
storename | ```metadata.name``` field in the user configured state store component yaml. Please refer Dapr State Store configuration structure mentioned above. `storename` | `metadata.name` field in the user-configured statestore.yaml component file. Refer to the [Dapr state store configuration structure](#component-file) mentioned above.
> Note, all URL parameters are case-sensitive. > Note, all URL parameters are case-sensitive.
@ -457,19 +453,18 @@ storename | ```metadata.name``` field in the user configured state store compone
Field | Description Field | Description
---- | ----------- ---- | -----------
operations | A JSON array of state operation `operations` | A JSON array of state operation
metadata | (optional) the metadata for transaction that applies to all operations `metadata` | (optional) The metadata for transaction that applies to all operations
Each state operation is comprised with the following fields: Each state operation is comprised with the following fields:
Field | Description Field | Description
---- | ----------- ---- | -----------
key | state key `key` | State key
value | state value, which can be any byte array `value` | State value, which can be any byte array
etag | (optional) state ETag `etag` | (optional) State ETag
metadata | (optional) additional key-value pairs to be passed to the state store `metadata` | (optional) Additional key-value pairs to be passed to the state store
options | (optional) state operation options, see [state operation options](#optional-behaviors) `options` | (optional) State operation options; see [state operation options](#optional-behaviors)
#### Examples #### Examples
@ -498,13 +493,12 @@ curl -X POST http://localhost:3500/v1.0/state/starwars/transaction \
}' }'
``` ```
## Configuring state store for actors ## Configuring state store for actors
Actors don't support multiple state stores and require a transactional state store to be used with Dapr. Currently Mongodb, Redis, PostgreSQL, SQL Server, and Azure CosmosDB implement the transactional state store interface. Actors don't support multiple state stores and require a transactional state store to be used with Dapr. [View which services currently implement the transactional state store interface]({{< ref "supported-state-stores.md" >}}).
To specify which state store to be used for actors, specify value of property `actorStateStore` as true in the metadata section of the state store component yaml file. Specify which state store to be used for actors with a `true` value for the property `actorStateStore` in the metadata section of the `statestore.yaml` component file.
Example: Following components yaml will configure redis to be used as the state store for Actors. For example, the following components yaml will configure Redis to be used as the state store for Actors.
```yaml ```yaml
apiVersion: dapr.io/v1alpha1 apiVersion: dapr.io/v1alpha1
@ -536,33 +530,35 @@ A Dapr-compatible state store shall use the following key scheme:
### Concurrency ### Concurrency
Dapr uses Optimized Concurrency Control (OCC) with ETags. Dapr makes optional the following requirements on state stores: Dapr uses Optimized Concurrency Control (OCC) with ETags. Dapr makes the following requirements optional on state stores:
* An Dapr-compatible state store may support optimistic concurrency control using ETags. When an ETag is associated with an *save* or *delete* request, the store shall allow the update only if the attached ETag matches with the latest ETag in the database. * A Dapr-compatible state store may support optimistic concurrency control using ETags. The store allows the update when an ETag:
* When ETag is missing in the write requests, the state store shall handle the requests in a last-write-wins fashion. This is to allow optimizations for high-throughput write scenarios in which data contingency is low or has no negative effects. * Is associated with an *save* or *delete* request.
* A store shall **always** return ETags when returning states to callers. * Matches the latest ETag in the database.
* When ETag is missing in the write requests, the state store shall handle the requests in a *last-write-wins* fashion. This allows optimizations for high-throughput write scenarios, in which data contingency is low or has no negative effects.
* A store shall *always* return ETags when returning states to callers.
### Consistency ### Consistency
Dapr allows clients to attach a consistency hint to *get*, *set* and *delete* operation. Dapr support two consistency level: **strong** and **eventual**, which are defined as the follows: Dapr allows clients to attach a consistency hint to *get*, *set*, and *delete* operation. Dapr supports two consistency levels: **strong** and **eventual**.
#### Eventual Consistency #### Eventual Consistency
Dapr assumes data stores are eventually consistent by default. A state should: Dapr assumes data stores are eventually consistent by default. A state should:
* For read requests, the state store can return data from any of the replicas * For *read* requests, return data from any of the replicas.
* For write request, the state store should asynchronously replicate updates to configured quorum after acknowledging the update request. * For *write* requests, asynchronously replicate updates to configured quorum after acknowledging the update request.
#### Strong Consistency #### Strong Consistency
When a strong consistency hint is attached, a state store should: When a strong consistency hint is attached, a state store should:
* For read requests, the state store should return the most up-to-date data consistently across replicas. * For *read* requests, return the most up-to-date data consistently across replicas.
* For write/delete requests, the state store should synchronisely replicate updated data to configured quorum before completing the write request. * For *write*/*delete* requests, synchronously replicate updated data to configured quorum before completing the write request.
### Example - Complete options request example ### Example: Complete options request example
The following is an example *set* request with a complete options definition: The following is an example *set* request with a complete `options` definition:
```shell ```shell
curl -X POST http://localhost:3500/v1.0/state/starwars \ curl -X POST http://localhost:3500/v1.0/state/starwars \
@ -580,82 +576,85 @@ curl -X POST http://localhost:3500/v1.0/state/starwars \
]' ]'
``` ```
### Example - Working with ETags ### Example: Working with ETags
The following is an example which walks through the usage of an ETag when setting/deleting an object in a compatible statestore.
First, store an object in a statestore (this sample uses Redis that has been defined as 'statestore'): The following is an example walk-through of an ETag usage when *setting*/*deleting* an object in a compatible state store. This sample defines Redis as `statestore`.
```shell 1. Store an object in a state store:
curl -X POST http://localhost:3500/v1.0/state/statestore \
-H "Content-Type: application/json" \
-d '[
{
"key": "sampleData",
"value": "1"
}
]'
```
Get the object to find the ETag that was set automatically by the statestore: ```shell
curl -X POST http://localhost:3500/v1.0/state/statestore \
-H "Content-Type: application/json" \
-d '[
{
"key": "sampleData",
"value": "1"
}
]'
```
```shell 1. Get the object to find the ETag set automatically by the state store:
curl http://localhost:3500/v1.0/state/statestore/sampleData -v
* Connected to localhost (127.0.0.1) port 3500 (#0)
> GET /v1.0/state/statestore/sampleData HTTP/1.1
> Host: localhost:3500
> User-Agent: curl/7.64.1
> Accept: */*
>
< HTTP/1.1 200 OK
< Server: fasthttp
< Date: Sun, 14 Feb 2021 04:51:50 GMT
< Content-Type: application/json
< Content-Length: 3
< Etag: 1
< Traceparent: 00-3452582897d134dc9793a244025256b1-b58d8d773e4d661d-01
<
* Connection #0 to host localhost left intact
"1"* Closing connection 0
```
The returned ETag here was 1. Sending a new request to update or delete the data with the wrong ETag will return an error (omitting the ETag will allow the request): ```shell
curl http://localhost:3500/v1.0/state/statestore/sampleData -v
* Connected to localhost (127.0.0.1) port 3500 (#0)
> GET /v1.0/state/statestore/sampleData HTTP/1.1
> Host: localhost:3500
> User-Agent: curl/7.64.1
> Accept: */*
>
< HTTP/1.1 200 OK
< Server: fasthttp
< Date: Sun, 14 Feb 2021 04:51:50 GMT
< Content-Type: application/json
< Content-Length: 3
< Etag: 1
< Traceparent: 00-3452582897d134dc9793a244025256b1-b58d8d773e4d661d-01
<
* Connection #0 to host localhost left intact
"1"* Closing connection 0
```
```shell The returned ETag above was 1. If you send a new request to update or delete the data with the wrong ETag, it will return an error. Omitting the ETag will allow the request.
# Update
curl -X POST http://localhost:3500/v1.0/state/statestore \
-H "Content-Type: application/json" \
-d '[
{
"key": "sampleData",
"value": "2",
"etag": "2"
}
]'
{"errorCode":"ERR_STATE_SAVE","message":"failed saving state in state store statestore: possible etag mismatch. error from state store: ERR Error running script (call to f_83e03ec05d6a3b6fb48483accf5e594597b6058f): @user_script:1: user_script:1: failed to set key nodeapp||sampleData"}
# Delete ```shell
curl -X DELETE -H 'If-Match: 5' http://localhost:3500/v1.0/state/statestore/sampleData # Update
{"errorCode":"ERR_STATE_DELETE","message":"failed deleting state with key sampleData: possible etag mismatch. error from state store: ERR Error running script (call to f_9b5da7354cb61e2ca9faff50f6c43b81c73c0b94): @user_script:1: user_script:1: failed to delete node curl -X POST http://localhost:3500/v1.0/state/statestore \
app||sampleData"} -H "Content-Type: application/json" \
``` -d '[
{
"key": "sampleData",
"value": "2",
"etag": "2"
}
]'
{"errorCode":"ERR_STATE_SAVE","message":"failed saving state in state store statestore: possible etag mismatch. error from state store: ERR Error running script (call to f_83e03ec05d6a3b6fb48483accf5e594597b6058f): @user_script:1: user_script:1: failed to set key nodeapp||sampleData"}
# Delete
curl -X DELETE -H 'If-Match: 5' http://localhost:3500/v1.0/state/statestore/sampleData
{"errorCode":"ERR_STATE_DELETE","message":"failed deleting state with key sampleData: possible etag mismatch. error from state store: ERR Error running script (call to f_9b5da7354cb61e2ca9faff50f6c43b81c73c0b94): @user_script:1: user_script:1: failed to delete node
app||sampleData"}
```
In order to update or delete the object, simply match the ETag in either the request body (update) or the `If-Match` header (delete). Note, when the state is updated, it receives a new ETag so further updates or deletes will need to use the new ETag. 1. Update or delete the object by simply matching the ETag in either the request body (update) or the `If-Match` header (delete). When the state is updated, it receives a new ETag that future updates or deletes will need to use.
```shell ```shell
# Update # Update
curl -X POST http://localhost:3500/v1.0/state/statestore \ curl -X POST http://localhost:3500/v1.0/state/statestore \
-H "Content-Type: application/json" \ -H "Content-Type: application/json" \
-d '[ -d '[
{ {
"key": "sampleData", "key": "sampleData",
"value": "2", "value": "2",
"etag": "1" "etag": "1"
} }
]' ]'
# Delete
curl -X DELETE -H 'If-Match: 1' http://localhost:3500/v1.0/state/statestore/sampleData
```
# Delete
curl -X DELETE -H 'If-Match: 1' http://localhost:3500/v1.0/state/statestore/sampleData
```
## Next Steps ## Next Steps
- [State management overview]({{< ref state-management-overview.md >}}) - [State management overview]({{< ref state-management-overview.md >}})
- [How-To: Save & get state]({{< ref howto-get-save-state.md >}}) - [How-To: Save & get state]({{< ref howto-get-save-state.md >}})