Conversation
| } | ||
| // Otherwise the execution was successful (almost certainly | ||
| // with errors), so log and return the result to the client. | ||
| log.warn("Unexpected rollback", ure); |
There was a problem hiding this comment.
could this leave the data in a bad state? is the expectation that the client would retry?
There was a problem hiding this comment.
I don't think so. The trivially reproducible case is querying for some field that requires authentication without a valid token. See the ExecutionResult below.
Under the covers, a principalAccess.getUser() call in the library.recipes field resolver threw a NoUserPrincipalException, which was caught and translated into a data fetching exception (by Spring), which gets added to the graphql errors. Then the part I don't fully understand occurs, where Spring exits the transaction, notices that it was rolled back when it didn't think it should have been, and throws.
From Spring's AbstractPlatformTransactionManager:
// Throw UnexpectedRollbackException if we have a global rollback-only
// marker but still didn't get a corresponding exception from commit.From a bit of digging, I think this happens when the transaction is marked as doomed, but an exception doesn't actually propagate all the way out to the transaction boundary (nor raised during commit). There's no exception to justify the rollback, so it's "unexpected".
In short, I believe that this is Spring saying "I rolled back your transaction because of something, but I don't have the exception, so I'll give you this one as a substitute." As such, it's safe to ignore, since it means the exception was resolved into a fetch error and not rethrown, so the result already has the interesting info. Which it does: Unauthorized.
{
"errors": [
{
"message": "Unauthorized",
"locations": [
{
"line": 9,
"column": 150
}
],
"path": [
"library",
"recipes"
],
"extensions": {
"classification": "UNAUTHORIZED"
}
}
],
"data": null
}There was a problem hiding this comment.
And this is why your explanations are vastly superior to any other source of information.
When Spring "unexpectedly" rolls back a transaction after a non-exceptional GraphQL execution completes, log and pass through the GraphQL result. This happens when something (e.g., a missing principal) causes an exception that rolls back the transaction, but which is then resolved into a data fetching error (e.g., "Unauthorized"). Since GraphQL doesn't use HTTP semantics, need to ensure Spring Web doesn't either.