-
Notifications
You must be signed in to change notification settings - Fork 17
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
Rework ConnectError to ConnectException #120
Conversation
Exceptions that might be caught should not extend throwable. Throwable is the subtype of both Exception and Error. The latter indicates a critical failure and should only be caught in very rare circumstances. This change renames the class and makes the supertype more specific to suggest that catching this throwable is reasonable.
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.
There are several other APIs that we should consider updating to use consistent names everywhere - i.e. connectError()
-> connectException()
.
Since we just made an API change in the last release, I wonder if we shouldn't hold off on changing ConnectError
-> ConnectException
everywhere so we can accumulate other API changes as well prior to stabilizing the API for a v1. Maybe we split this PR into two - first doing the Throwable -> Exception change and then saving another with a full rename to merge along with other API changes.
Co-authored-by: Philip K. Warren <[email protected]>
Changing the super type isn't a source breaking change, but it does break the API contract because some people might be depending on the super type being I'll look through a little more carefully for other parts of the API surface that need a name update. I get the concern with a breaking change (especially successive ones). I understand if we want to leave this open a while. Have y'all considered keeping a changelog in the repo? It might make changes like this one more palatable for early adopters. Edit: the super type change could be a breaking change in certain generic type bound situations, upon further thought. |
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.
A few more spots need to be updated:
grpcCompletionToConnectError
->grpcCompletionToConnectException
.connectErr
->connectExcception
in conformance tests and the Main.kt examples.ServerStreamingResult.error
->exception
in the conformance tests.parseConnectUnaryError
->parseConnectUnaryException
.
I think we should also change the following for consistency:
ResponseMessage.Failure.error
->exception
orcause
.StreamResult.Complete.error
->exception
orcause
.HTTPResponse.error
->exception
orcause
.
In most (3 of 4) uses of this method, the first argument was known to be non-null at the call site. Since in the event that the first argument _was_ null, we basically create a `ConnectException` without much helpful information about any error, it made sense to me to remove the concept of a nullable completion from the method entirely. The function is also a little more idiomatic now, following the typical `to<Type>OrNull` pattern established by the language for conversion between types. It also reduces the classes generated by the compiler since the method is a proper member of `GRPCCompletion`. I would probably push this idea a little further in how error states are modeled more generally, but that's creeping outside the scope of this change.
3a8f81c
to
0cfee73
Compare
I think the remaining issues are addressed. I was able to verify the conformance tests compile, but I'm not able to run them. I'll keep an eye on the PR checks when they're run. Thanks! Note the extended commit message in 4c10702 |
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.
Looks great!
* Converts a completion into a [ConnectException] if the completion failed or if a throwable is passed | ||
* @return a ConnectException on failure, null otherwise | ||
*/ | ||
fun toConnectExceptionOrNull(serializationStrategy: SerializationStrategy, cause: Throwable? = null): ConnectException? { |
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.
Nice refactoring here.
Looks like the lint check is failing - if you run |
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.
Blocking for now until we can address conformance tests and lint warnings.
The assertions in the conformance tests don't print the assertion message. This makes debugging via CI difficult. I don't have a docker license, so I can't run them locally. |
trailers = trailers, | ||
) | ||
} else { | ||
val exception = ConnectException(Code.UNKNOWN) |
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.
To resolve the test failure, this else condition should change to:
return@fold result
This way we'll preserve errors like DEADLINE_EXCEEDED
.
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 whole if-else is an expression, which should resolve to L169 if completion != null
and L176 otherwise. Could you elaborate on why this callback needs a non-local return and the others don't? It seems like the expression should bubble up where it needs to go via fold
, like the onHeaders
and onMessage
callbacks.
I'm happy to make that change, but I'm aiming to understand it better first.
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.
So result is already instantiated in some cases (with a code like DEADLINE_EXCEEDED and a cause). Some of the tests rely on this. Alternatively to doing return@fold
. you could just have result
here as the return value.
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.
I'm tracking now. Thanks for the explaination.
) | ||
} else { | ||
val exception = ConnectException(result.code) | ||
StreamResult.Complete(exception.code, exception, trailers) |
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.
We may be losing an underlying cause here - so we should just return the result here.
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.
I worked around the problem by using the result's code property value in the connect exception constructor, but I like that idea better.
Exceptions that might be caught should not extend throwable. Throwable
is the subtype of both Exception and Error. The latter indicates a
critical failure and should only be caught in very rare circumstances.
This change renames the class and makes the supertype more specific
to suggest that catching this throwable is reasonable.
Before submitting your PR: Please read through the contribution guide at https://github.com/connectrpc/connect-kotlin/blob/main/.github/CONTRIBUTING.md
Note: This is a source-breaking change, which was briefly discussed in slack.