Skip to content

Adjust parent types for exceptions #1924

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

Merged
merged 6 commits into from
Nov 15, 2021

Conversation

idelpivnitskiy
Copy link
Member

@idelpivnitskiy idelpivnitskiy commented Oct 29, 2021

Motivation:

After revisiting all existing exception types, we found that some of
them use incorrect parent type.

Modifications:

  • Use more appropriate parent type for existing exceptions:
    • ConnectionRejectedException extend RuntimeException -> SocketException;
    • NoAvailableHostException extend RuntimeException -> IOException;
    • DuplicateAttributeException extend RuntimeException -> IllegalStateException;
    • TerminateRepeatException extend Exception -> RuntimeException;
    • ClosedServiceDiscovererException extend RuntimeException -> ClosedChannelException;
    • UnsupportedHttpChunkException extend SerializationException -> IllegalArgumentException;
  • Regenerate serialVersionUID for updated exception classes;
  • Use StacklessConnectionRejectedException for
    RoundRobinLoadBalancer;
  • Mark MessageEncodingException as @Deprecated (was missed during rework of
    serialization API);
  • Remove unused ctor from ResponseTimeoutTest;

Result:

Exceptions have more appropriate parent types.

Motivation:

After revisiting all existing exception types, we found that some of
them use incorrect parent type.

Modifications:

- Use more appropriate parent type for existing exceptions;
- Regenerate `serialVersionUID` for updated exception classes;
- Fix how the message is generated for `MessageEncodingException`;
- Change exception type thrown by
`DefaultMultiAddressUrlHttpClientBuilder` to `MalformedURLException`
when request target is not in absolute-form;
- Remove unused ctor from `ResponseTimeoutTest`;
- Use `StacklessConnectionRejectedException` for
`RoundRobinLoadBalancer`;

Result:

Exceptions have more appropriate parent types.
@idelpivnitskiy idelpivnitskiy added the breaking-change PR with breaking changes, removed APIs or other binary incompatibilities. label Oct 29, 2021
@idelpivnitskiy idelpivnitskiy self-assigned this Oct 29, 2021
Copy link
Member Author

@idelpivnitskiy idelpivnitskiy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't expect it to be an impactful breaking change because most of the users use our types instead of parent types. Should be an appropriate change for 0.42 release, wdyt?

/**
* Thrown when a newly created connection was rejected.
*/
public final class ConnectionRejectedException extends RuntimeException implements RetryableException {
private static final long serialVersionUID = -2573006397795678870L;
public class ConnectionRejectedException extends SocketException implements RetryableException {
Copy link
Member Author

@idelpivnitskiy idelpivnitskiy Oct 29, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Debated between ConnectException and SocketException. Based on their javadoc, decided to go with SocketException because technically the connection was already established, but there was a problem "accessing" it due to a selector or a host becoming unavailable.

@@ -40,8 +40,8 @@
/**
* An {@link Exception} instance used to indicate termination of repeats.
*/
public static final class TerminateRepeatException extends Exception {
private static final long serialVersionUID = -1725458427890873886L;
public static final class TerminateRepeatException extends RuntimeException {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The decision to throw this exception happens at runtime

*/
@Deprecated
public final class MessageEncodingException extends RuntimeException {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ProtoBufSerializationProviderBuilder was deprecated only in the main branch, we don't need to cherry-pick this into 0.41

import javax.annotation.Nullable;

final class UnsupportedHttpChunkException extends SerializationException {
final class UnsupportedHttpChunkException extends IllegalArgumentException {
Copy link
Member Author

@idelpivnitskiy idelpivnitskiy Oct 29, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The change from IllegalArgumentException to SerializationException was made only in the main branch in #1673. This is not related to serialization and more about what payload body object users passed to an HTTP message. Reverting back to IllegalArgumentException.
cc @Scottmitch

return defer(() -> {
try {
return selectClient(request).request(strategy, request).subscribeShareContext();
} catch (Throwable t) {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The try-catch here is necessary anyway, because methods that return async sources are not expected to throw.

/**
* Thrown when no host is available but at least one is required.
*/
public class NoAvailableHostException extends RuntimeException implements RetryableException {
private static final long serialVersionUID = 5340791072245425967L;
public class NoAvailableHostException extends SocketException implements RetryableException {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it a "SocketException"? I would rather keep it a runtime one or associate with a LB/SD parent type.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The intend was to make it IOException because it prevents a request execution due to unavailability to execute an IO operation. During offline discussion, @bondolo recommended a more specific subtype - SocketException. I'm agreed with that proposal because it notifies that there are no sockets available at this point of time.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't see a reason to block the change but I don't agree that this is a good correlation. I agree that IOException is a valid super type, but SocketException is clearly doc'ed to do with failure to access or create a socket. In our case this is not even related to a connection but rather to host-finding.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, I was reading "failure to access a socket" as "no hosts -> no access" 😄
Changing to IOException: c2b41cf

@@ -63,6 +64,9 @@
* A builder of {@link StreamingHttpClient} instances which have a capacity to call any server based on the parsed
* absolute-form URL address information from each {@link StreamingHttpRequest}.
* <p>
* If {@link HttpRequestMetaData#requestTarget()} is not an absolute-form URL, a {@link MalformedURLException} will be
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Possibly just a personal preference but I usually prefer URISyntaxException to MalformedURLException because the later often gets handled as a generic IOException by lazy people who hate checked exceptions.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm... Haven't thought about URISyntaxException. Reading its javadoc, it's hard to say that /path is expected to trigger URISyntaxException. Description of MalformedURLException is better aligned with multi-address client requirements. What others think?

I'm agreed that users usually catch broad IOException. A good thing with Reactive Streams is that you don't have to throw and try-catch checked exceptions, everything is propagated through onError as Throwable.
BlockingHttpClient signature defines a request method as throws Exception.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've opened a separate PR #1955 for this change to make it move visible in release notes

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
breaking-change PR with breaking changes, removed APIs or other binary incompatibilities.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants