Ignore 404 errors in transactional cosmos delete operations (#3894)

Signed-off-by: Albert Callarisa <albert@diagrid.io>
This commit is contained in:
Albert Callarisa 2025-07-22 15:26:32 +02:00 committed by GitHub
parent 1fdd75336d
commit c173b024c5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 56 additions and 13 deletions

View File

@ -567,14 +567,27 @@ func (c *StateStore) Multi(ctx context.Context, request *state.TransactionalStat
}
if !batchResponse.Success {
// Transaction failed, look for the offending operation
var transactionError error
for index, operation := range batchResponse.OperationResults {
// delete operations with no etag check are allowed to fail with a 404
deleteReq, isDelete := request.Operations[index].(state.DeleteRequest)
if isDelete && operation.StatusCode == http.StatusNotFound && !deleteReq.HasETag() {
continue
}
if operation.StatusCode != http.StatusFailedDependency {
c.logger.Errorf("Transaction failed due to operation %v which failed with status code %d", index, operation.StatusCode)
return fmt.Errorf("transaction failed due to operation %v which failed with status code %d", index, operation.StatusCode)
}
transactionError = errors.New("transaction failed")
}
// If all errors are from delete operations with a 404 (and no etag check), we end up here with a nil error.
// This is expected, as we allow delete operations to fail with a 404.
if transactionError != nil {
return transactionError
}
return errors.New("transaction failed")
}
// Transaction succeeded

View File

@ -296,8 +296,8 @@ func ConformanceTests(t *testing.T, props map[string]string, statestore state.St
query: `
{
"filter": {
"OR": [
{
"OR": [
{
"AND": [
{
"EQ": {"message": "` + key + `message"}
@ -310,7 +310,7 @@ func ConformanceTests(t *testing.T, props map[string]string, statestore state.St
}
]
},
{
{
"AND": [
{
"EQ": {"message": "` + key + `message"}
@ -702,6 +702,27 @@ func ConformanceTests(t *testing.T, props map[string]string, statestore state.St
}
})
t.Run("delete non-existent key", func(t *testing.T) {
// for CosmosDB
partitionMetadata := map[string]string{
"partitionKey": "myPartition",
}
operations := []state.TransactionalStateOperation{
state.DeleteRequest{
Key: "non-existent-key",
},
}
transactionStore, ok := statestore.(state.TransactionalStore)
require.True(t, ok)
err := transactionStore.Multi(t.Context(), &state.TransactionalStateRequest{
Operations: operations,
Metadata: partitionMetadata,
})
require.NoError(t, err)
})
t.Run("transaction-order", func(t *testing.T) {
// Arrange
firstKey := key + "-key1"
@ -796,6 +817,12 @@ func ConformanceTests(t *testing.T, props map[string]string, statestore state.St
metadataTest1 := map[string]string{
"contentType": "application/json",
// for CosmosDB
"partitionKey": "myPartition",
}
metadataTest2 := map[string]string{
// for CosmosDB
"partitionKey": "myPartition",
}
operations := []state.TransactionalStateOperation{
@ -817,6 +844,7 @@ func ConformanceTests(t *testing.T, props map[string]string, statestore state.St
expectedMetadata := map[string]map[string]string{
keyTest1: metadataTest1,
keyTest2: metadataTest2,
}
// Act
@ -824,6 +852,9 @@ func ConformanceTests(t *testing.T, props map[string]string, statestore state.St
assert.True(t, ok)
err := transactionStore.Multi(t.Context(), &state.TransactionalStateRequest{
Operations: operations,
Metadata: map[string]string{
"partitionKey": "myPartition",
},
})
require.NoError(t, err)
@ -833,17 +864,16 @@ func ConformanceTests(t *testing.T, props map[string]string, statestore state.St
Key: k,
Metadata: expectedMetadata[k],
})
expectedValue := res.Data
require.NoError(t, err)
receivedValue := res.Data
// In redisjson when set the value with contentType = application/Json store the value in base64
if strings.HasPrefix(string(expectedValue), "\"ey") {
valueBase64 := strings.Trim(string(expectedValue), "\"")
expectedValueDecoded, _ := base64.StdEncoding.DecodeString(valueBase64)
require.NoError(t, err)
assert.Equal(t, expectedValueDecoded, v)
if strings.HasPrefix(string(receivedValue), "\"ey") {
valueBase64 := strings.Trim(string(receivedValue), "\"")
receivedValueDecoded, _ := base64.StdEncoding.DecodeString(valueBase64)
assert.JSONEq(t, string(v), string(receivedValueDecoded))
} else {
require.NoError(t, err)
assert.Equal(t, expectedValue, v)
assert.JSONEq(t, string(v), string(receivedValue))
}
}
}