Skip to content

Commit

Permalink
Update statestore ETag/actor support (#1213)
Browse files Browse the repository at this point in the history
* Update statestore ETag/actor support

Add additional column to the supporte statestore table that
indicates direct support of ETag usage. Also specify that
transactional stores support actors.

#1199

* Add ETag example in statestore API reference

This commit adds a walkthrough of how to work with ETags including
finding them and using them for updates and deletes.

* Update _index.md

* Update state_api.md

Co-authored-by: Mark Fussell <mfussell@microsoft.com>
Co-authored-by: Yaron Schneider <yaronsc@microsoft.com>
  • Loading branch information
3 people committed Feb 15, 2021
1 parent 778ebf9 commit de42e45
Show file tree
Hide file tree
Showing 3 changed files with 111 additions and 35 deletions.
Expand Up @@ -26,13 +26,7 @@ Actors can save state reliably using state management capability.

You can interact with Dapr through HTTP/gRPC endpoints for state management.

To use actors, your state store must support multi-item transactions. This means your state store [component](https://github.com/dapr/components-contrib/tree/master/state) must implement the [TransactionalStore](https://github.com/dapr/components-contrib/blob/master/state/transactional_store.go) interface. The following state stores implement this interface:

- Redis
- MongoDB
- PostgreSQL
- SQL Server
- Azure CosmosDB
To use actors, your state store must support multi-item transactions. This means your state store [component](https://github.com/dapr/components-contrib/tree/master/state) must implement the [TransactionalStore](https://github.com/dapr/components-contrib/blob/master/state/transactional_store.go) interface. The list of components that support transactions/actors can be found here: [supported state stores]({{< ref supported-state-stores.md >}}).

## Actor timers and reminders

Expand Down
Expand Up @@ -9,32 +9,36 @@ no_list: true

### Generic

| Name | CRUD | Transactional | Status |
|----------------------------------------------------------------|------|---------------|--------|
| [Aerospike]({{< ref setup-aerospike.md >}}) ||| Alpha |
| [Apache Cassandra]({{< ref setup-cassandra.md >}}) ||| Alpha |
| [Cloudstate]({{< ref setup-cloudstate.md >}}) ||| Alpha |
| [Couchbase]({{< ref setup-couchbase.md >}}) ||| Alpha |
| [Hashicorp Consul]({{< ref setup-consul.md >}}) ||| Alpha |
| [Hazelcast]({{< ref setup-hazelcast.md >}}) ||| Alpha |
| [Memcached]({{< ref setup-memcached.md >}}) ||| Alpha |
| [MongoDB]({{< ref setup-mongodb.md >}}) ||| Alpha |
| [MySQL]({{< ref setup-mysql.md >}}) ||| Alpha |
| [PostgreSQL]({{< ref setup-postgresql.md >}}) ||| Alpha |
| [Redis]({{< ref setup-redis.md >}}) ||| Alpha |
| [Zookeeper]({{< ref setup-zookeeper.md >}}) ||| Alpha |
| Name | CRUD | Transactional </br>(Supports Actors) | ETag | Status |
|----------------------------------------------------------------|------|---------------------|------|--------|
| [Aerospike]({{< ref setup-aerospike.md >}}) |||| Alpha |
| [Apache Cassandra]({{< ref setup-cassandra.md >}}) |||| Alpha |
| [Cloudstate]({{< ref setup-cloudstate.md >}}) |||| Alpha |
| [Couchbase]({{< ref setup-couchbase.md >}}) |||| Alpha |
| [Hashicorp Consul]({{< ref setup-consul.md >}}) |||| Alpha |
| [Hazelcast]({{< ref setup-hazelcast.md >}}) |||| Alpha |
| [Memcached]({{< ref setup-memcached.md >}}) |||| Alpha |
| [MongoDB]({{< ref setup-mongodb.md >}}) |||| Alpha |
| [MySQL]({{< ref setup-mysql.md >}}) |||| Alpha |
| [PostgreSQL]({{< ref setup-postgresql.md >}}) |||| Alpha |
| [Redis]({{< ref setup-redis.md >}}) |||| Alpha |
| RethinkDB |||| Alpha |
| [Zookeeper]({{< ref setup-zookeeper.md >}}) |||| Alpha |

### Google Cloud Platform (GCP)
| Name | CRUD | Transactional | Status |
|-------------------------------------------------------|------|---------------|--------|
| [GCP Firestore]({{< ref setup-firestore.md >}}) ||| Alpha |
| Name | CRUD | Transactional </br>(Supports Actors) | ETag | Status |
|-------------------------------------------------------|------|---------------------|------|--------|
| [GCP Firestore]({{< ref setup-firestore.md >}}) || || Alpha |
### Microsoft Azure

| Name | CRUD | Transactional | Status |
|------------------------------------------------------------------|------|---------------|--------|
| [Azure Blob Storage]({{< ref setup-azure-blobstorage.md >}}) ||| Alpha |
| [Azure CosmosDB]({{< ref setup-azure-cosmosdb.md >}}) ||| Alpha |
| [Azure SQL Server]({{< ref setup-sqlserver.md >}}) ||| Alpha |
| [Azure Table Storage]({{< ref setup-azure-tablestorage.md >}}) ||| Alpha |

| Name | CRUD | Transactional </br>(Supports Actors) | ETag | Status |
|------------------------------------------------------------------|------|---------------------|------|--------|
| [Azure Blob Storage]({{< ref setup-azure-blobstorage.md >}}) |||| Alpha |
| [Azure CosmosDB]({{< ref setup-azure-cosmosdb.md >}}) |||| Alpha |
| [Azure SQL Server]({{< ref setup-sqlserver.md >}}) |||| Alpha |
| [Azure Table Storage]({{< ref setup-azure-tablestorage.md >}}) |||| Alpha |

### Amazon Web Services (AWS)
| Name | CRUD | Transactional </br>(Supports Actors) | ETag | Status |
|------------------------------------------------------------------|------|---------------------|------|--------|
| AWS DynamoDB |||| Alpha |
86 changes: 82 additions & 4 deletions daprdocs/content/en/reference/api/state_api.md
Expand Up @@ -103,7 +103,8 @@ curl -X POST http://localhost:3500/v1.0/state/starwars \
-d '[
{
"key": "weapon",
"value": "DeathStar"
"value": "DeathStar",
"etag": "1234"
},
{
"key": "planet",
Expand Down Expand Up @@ -288,7 +289,7 @@ None.
### Example

```shell
curl -X "DELETE" http://localhost:3500/v1.0/state/starwars/planet -H "ETag: xxxxxxx"
curl -X "DELETE" http://localhost:3500/v1.0/state/starwars/planet -H "If-Match: xxxxxxx"
```

## State transactions
Expand Down Expand Up @@ -377,6 +378,7 @@ curl -X POST http://localhost:3500/v1.0/state/starwars/transaction \
## 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.

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.
Example: Following components yaml will configure redis to be used as the state store for Actors.

Expand Down Expand Up @@ -434,9 +436,9 @@ 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 write/delete requests, the state store should synchronisely replicate updated data to configured quorum before completing the write request.

### Example
### Example - Complete options request example

The following is a sample *set* request with a complete operation option definition:
The following is an example *set* request with a complete options definition:

```shell
curl -X POST http://localhost:3500/v1.0/state/starwars \
Expand All @@ -454,6 +456,82 @@ curl -X POST http://localhost:3500/v1.0/state/starwars \
]'
```

### 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'):

```shell
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 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
# 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
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.
```shell
# Update
curl -X POST http://localhost:3500/v1.0/state/statestore \
-H "Content-Type: application/json" \
-d '[
{
"key": "sampleData",
"value": "2",
"etag": "1"
}
]'

# Delete
curl -X DELETE -H 'If-Match: 1' http://localhost:3500/v1.0/state/statestore/sampleData
```
## Next Steps
- [State management overview]({{< ref state-management-overview.md >}})
- [How-To: Save & get state]({{< ref howto-get-save-state.md >}})

0 comments on commit de42e45

Please sign in to comment.