go-sdk
go-sdk copied to clipboard
SaveBulkState panic: error saving state: rpc error: code = Internal desc = failed saving state in state store statestore: no item was updated
Describe the bug When I use state.postgresql as statestore,save data failed. When I use redis statestore,save data success.
To Reproduce postgres.yaml statestore config file:
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
name: statestore
spec:
type: state.postgresql
version: v1
metadata:
- name: connectionString
value: "host=localhost user=root password=password port=5432 connect_timeout=10 database=statestore"
- name: actorStateStore
value: "true"
redis.yaml statestore config file:
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
name: statestore
spec:
type: state.redis
version: v1
metadata:
- name: redisHost
value: localhost:6379
- name: redisPassword
value: ""
- name: actorStateStore
value: "true"
app code is:
func main() {
client, err := dapr.NewClient()
if err != nil {
panic(err)
}
defer client.Close()
//TODO: use the client here, see below for examples
ctx := context.Background()
store := "statestore" // defined in the component YAML
data := []byte("hello")
item1 := &dapr.SetStateItem{
Key: "key11",
Etag: &dapr.ETag{
Value: "1",
},
Metadata: map[string]string{
"created-on": time.Now().UTC().String(),
},
Value: []byte("hello"),
Options: &dapr.StateOptions{
Concurrency: dapr.StateConcurrencyLastWrite,
Consistency: dapr.StateConsistencyStrong,
},
}
item2 := &dapr.SetStateItem{
Key: "key21",
Metadata: map[string]string{
"created-on": time.Now().UTC().String(),
},
Value: []byte("hello again"),
}
item3 := &dapr.SetStateItem{
Key: "key31",
Etag: &dapr.ETag{
Value: "1",
},
Value: []byte("hello again"),
}
if err := client.SaveBulkState(ctx, store, item1, item2, item3); err != nil {
panic(err)
}
keys := []string{"key11", "key21", "key31"}
_, err = client.GetBulkState(ctx, store, keys, nil, 100)
if err != nil {
panic(err)
}
}
error:
== APP == dapr client initializing for: 127.0.0.1:51916
== APP == panic: error saving state: rpc error: code = Internal desc = failed saving state in state store statestore: no item was updated
== APP ==
== APP == goroutine 1 [running]:
== APP == main.main()
== APP == I:/MyProjects/main.go:71 +0xafd
== APP == exit status 2
== APP == data [key:key1 etag:775]: hello
**Expected behavior**
Need SaveBulkState success
I found that Redis and pgSQL behave differently. For pgSQL, creating a State with the wrong ETag will report an error, while Redis does not have this problem.
The following code exposes the problem better. It will report an error in pgSQL, but not in Redis.
item1 := &dapr.SetStateItem{
Key: "key1",
Value: []byte("hello"),
Etag: &dapr.ETag{
Value: "1",
},
}
if err := client.SaveBulkState(ctx, store, item1); err != nil {
// report an error
fmt.Printf("create with wrong ETag will failed in pgSQL, err = %s", err)
}
// should create without ETag
item1 = &dapr.SetStateItem{
Key: "key1",
Value: []byte("hello"),
}
if err := client.SaveBulkState(ctx, store, item1); err != nil {
panic(err)
}
// update with ETag
item1Resp, err := client.GetState(ctx, store, "key1", nil)
if err != nil {
panic(err)
}
newItem1 := &dapr.SetStateItem{
Key: "key1",
Value: []byte("hello again"),
Etag: &dapr.ETag{Value: item1Resp.Etag},
}
if err := client.SaveBulkState(ctx, store, newItem1); err != nil {
panic(err)
}
Also, I found that in the Python SDK, even Redis can't pass the wrong ETag at creating state. https://github.com/dapr/python-sdk/tree/master/examples/state_store