-
Notifications
You must be signed in to change notification settings - Fork 543
Conformance tests & bugfixes for SQLServer #1078
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
.github/infrastructure/conformance/azure/setup-azure-conf-test.sh
Outdated
Show resolved
Hide resolved
CodeMonkeyLeet
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for all the hard work digging into this! The stored proc logic still seems iffy to me though, might want to check with the maintainers as to the expectations here.
.github/infrastructure/conformance/azure/setup-azure-conf-test.sh
Outdated
Show resolved
Hide resolved
artursouza
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great progress. It is almost there.
d367468 to
d60c2e1
Compare
|
@artursouza sorry for all the confusion here. I believe I was able to address all concerns and was also able to simplify some error handling. Please note that the code changed can't meaningfully be tested via unit tests -- there are no similar unit tests today. There are however integration tests at |
artursouza
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM. Thanks for revisiting the logic in the stored procedure. Please, wait for approval from @CodeMonkeyLeet too.
CodeMonkeyLeet
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See extended discussion on existing questions on error state handling. I'm okay with taking the PR, modulo tracking ongoing issues in the concurrency handling contract in Dapr.
| IF NOT EXISTS (SELECT * FROM [%s] WHERE [KEY]=@KEY AND RowVersion = @RowVersion) | ||
| BEGIN | ||
| THROW 2601, ''FIRST-WRITE: COMPETING RECORD ALREADY WRITTEN.'', 1 | ||
| END |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is not always the case though: this case can also be because the row was never written before and the key does not exist.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's an excellent point. What do you suggest? Changing the error message?
If the record does not exist it's not actually possible to specify an ETAG (Row Version) to be written -- the stored procedure / DB won't allow the use of ETAGs other than to update an existing record.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I would just change the error message to something more general
| SET [Data]=@Data, UpdateDate=GETDATE() | ||
| WHERE [Key]=@Key AND RowVersion = ISNULL(@RowVersion, RowVersion) | ||
| END CATCH`, | ||
| CREATE PROCEDURE %s ( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall, I think the logic here is still problematic. I understand the desire not to churn existing code, but it looks like there are still issues relative to the expected behaviors expressed in #2739 1c. Condensed here for reference:
| StateOptions.Concurrency | Req.Etag | Expected Behavior in State Store |
|---|---|---|
| CONCURRENCY_FIRST_WRITE | not nil | Write if etag matches |
| CONCURRENCY_FIRST_WRITE | nil | Write if key does not exist |
| CONCURRENCY_LAST_WRITE or unspecified | not nil | Return error (Upcoming breaking change. Today, state components write regardless of etag) |
| CONCURRENCY_LAST_WRITE or unspecified | nil | Write regardless of etag |
"Write" in this case refers to an upsert (i.e. insert key if it does not already exist, otherwise update). The original code ignores the top half of that table, but it also looks like it already did not implement the bottom half correctly. Please correct any readings of the code here:
- If an ETag is provided and the key does not exist, it attempts to update, which returns 0 rows modified but does not error and does not insert the value. It is silently lost.
- If an ETag is provided and the key does exist, it will attempt to update using the ETag. If the ETag does not match, it again does not error and does not update the value, which has FIRST_WRITE semantics instead of LAST_WRITE (default) semantics. It should ignore the ETag completely in this case.
Preserving the original logic propagates these issues forwards. The new logic for handling FIRST_WRITE works, although it raises some questions about the specification for behavior:
- If ETag provided and key does not exist, ETag can never match. Should the method raise an error or silently ignore the write?
- This implementation returns an error
- If ETag provided and key exists, but ETag does not match, should the method raise an error or silently ignore the write?
- This implementation silently ignores the update. (The update on row 290 finds no matches).
That seems potentially inconsistent as an error contract for Dapr.
@artursouza To keep this moving forwards, since you've already approved the PR and the new code is okay, I suggest we file a separate issue to track the logical inconsistencies in the existing code. In continuing the discussion of Dapr ETag/concurrency state handling, I'll also follow up on the issue with my questions on the expected error handling.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The issue for LAST_WRITE and eTag not null is behavior change beyond the scope of this change because it is a broader concern of the expectations for the state API behavior. I am OK with the current logic in this component.
The error handling for silent etag mistmatch in the stored procedure is handled in code by checking number of rows affected.
@CodeMonkeyLeet Let me know if you have any other concerns on this PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nope, I think it's definitely a step forward and we should take it, thanks for reminding me about the downstream handling of returning errors from the zero rows updated check.
Co-authored-by: Simon Leet <31784195+CodeMonkeyLeet@users.noreply.github.com>
Co-authored-by: Simon Leet <31784195+CodeMonkeyLeet@users.noreply.github.com>
Codecov Report
@@ Coverage Diff @@
## master #1078 +/- ##
==========================================
- Coverage 34.53% 33.98% -0.55%
==========================================
Files 132 134 +2
Lines 10870 11283 +413
==========================================
+ Hits 3754 3835 +81
- Misses 6736 7057 +321
- Partials 380 391 +11
Continue to review full report at Codecov.
|
* enable sqlserver conformance test * Update SQL Server conformance test setup * Fix sqlserver bug introduced in Go 1.16 * sqlserver almost conformant * Fix conformance tests and stored procedure * all sqlserver tests passing * Minor touchup * lint * Remove unnecessary condition * Add conformance test to GitHub workflow * remove env variable * Update stored procedure * Simplify error handling * Update state/sqlserver/sqlserver.go Co-authored-by: Simon Leet <31784195+CodeMonkeyLeet@users.noreply.github.com> * Update state/sqlserver/sqlserver.go Co-authored-by: Simon Leet <31784195+CodeMonkeyLeet@users.noreply.github.com> Co-authored-by: Bernd Verst <me@bernd.dev> Co-authored-by: Simon Leet <31784195+CodeMonkeyLeet@users.noreply.github.com> Co-authored-by: Artur Souza <artursouza.ms@outlook.com> Co-authored-by: Dapr Bot <56698301+dapr-bot@users.noreply.github.com>
Description
Adds conformance tests to and fixes bugs in the SqlServer state store component.
The new conformance test suite has been added to the GitHub workflow and has already successfully run as part of this PR.
Conformance tests can manually be run like so:
Integration tests can then be run via the following which checks for the same variable to be set
Note that I did not add the
DAPR_TEST_SQL_CONNSTRINGvariable. This has been in the code for a long time.Issue reference
#949
Fixes #1036
Checklist
Please make sure you've completed the relevant tasks for this PR, out of the following list: