Skip to content
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

fix: connection closed prematurely in BlobReadChannel & ConnectionReset #173

Merged
merged 10 commits into from Mar 13, 2020

Conversation

frankyn
Copy link
Member

@frankyn frankyn commented Mar 11, 2020

Fixes #165

Introduce:

  • public StorageException(int code, String message, String reason, Throwable cause):
    to capture the reason which is used to check RETRYABLE_ERRORS.
  • public static StorageException translate(IOException exception): to help translate idempotent request exceptions in case they're RETRYABLE_ERRORS. This translate method should be introduced for other idempotent requests, but that's out of scope for this request.

@googlebot googlebot added the cla: yes This human has signed the Contributor License Agreement. label Mar 11, 2020
@codecov
Copy link

codecov bot commented Mar 11, 2020

Codecov Report

Merging #173 into master will increase coverage by 0.01%.
The diff coverage is 66.66%.

Impacted file tree graph

@@             Coverage Diff              @@
##             master     #173      +/-   ##
============================================
+ Coverage     63.46%   63.48%   +0.01%     
- Complexity      537      540       +3     
============================================
  Files            30       30              
  Lines          4752     4760       +8     
  Branches        427      428       +1     
============================================
+ Hits           3016     3022       +6     
- Misses         1576     1577       +1     
- Partials        160      161       +1
Impacted Files Coverage Δ Complexity Δ
...om/google/cloud/storage/spi/v1/HttpStorageRpc.java 1.63% <0%> (ø) 1 <0> (ø) ⬇️
...ava/com/google/cloud/storage/StorageException.java 92.3% <75%> (-7.7%) 9 <3> (+3)

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 1617c40...e918305. Read the comment docs.

@frankyn frankyn changed the title fix: connection closed prematurely in BlobReadChannel fix: connection closed prematurely in BlobReadChannel & ConnectionReset Mar 11, 2020
@frankyn frankyn requested a review from elharo March 11, 2020 16:35
} else if (serviceException.getMessage().contains("Connection closed prematurely")) {
serviceException = new StorageException(new SocketException(serviceException.getMessage()));
} else if (serviceException.getMessage().contains("Connection reset")) {
serviceException = new StorageException(new SocketException(serviceException.getMessage()));
Copy link
Contributor

Choose a reason for hiding this comment

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

This loses the stack trace; you should include the servieException too

@@ -704,6 +705,10 @@ public long read(
StorageException serviceException = translate(ex);
if (serviceException.getCode() == SC_REQUESTED_RANGE_NOT_SATISFIABLE) {
return Tuple.of(null, new byte[0]);
} else if (serviceException.getMessage().contains("Connection closed prematurely")) {
serviceException = new StorageException(new SocketException(serviceException.getMessage()));
Copy link
Contributor

Choose a reason for hiding this comment

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

This is very weird. I don't think I've ever seen this double wrapping in one throw clause done before. Can you explain the purpose here and how it works?

@@ -84,6 +84,85 @@ public void testCreate() {
assertTrue(reader.isOpen());
}

@Test
public void testCreateRetryableErrorPrematureClosure() throws IOException {
byte[] arr = {0x0, 0xd, 0xa};
Copy link
Contributor

Choose a reason for hiding this comment

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

array (no abbreviations per Google style)


@Test
public void testCreateNonRetryableErrorPrematureClosure() throws IOException {
byte[] arr = {0x0, 0xd, 0xa};
Copy link
Contributor

Choose a reason for hiding this comment

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

array

expect(storageRpcMock.read(BLOB_ID.toPb(), EMPTY_RPC_OPTIONS, 0, 2097152)).andThrow(exception);
replay(storageRpcMock);
try {
assertTrue(reader.read(byteBuffer) > 0);
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 both assertTrue and fail

@@ -226,6 +226,7 @@ public void onFailure(GoogleJsonError googleJsonError, HttpHeaders httpHeaders)
}

private static StorageException translate(IOException exception) {

Choose a reason for hiding this comment

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

Do we run a formatter for java? Is this blank line a problem for it?

Copy link
Member Author

Choose a reason for hiding this comment

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

It doesn't clean it up surprisingly.

@frankyn frankyn requested review from elharo and crwilcox and removed request for chingor13 March 12, 2020 00:36
@frankyn frankyn requested a review from chingor13 March 12, 2020 00:55
@@ -43,7 +46,9 @@
new Error(500, null),
Copy link
Contributor

Choose a reason for hiding this comment

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

Where does this Error class come from?

Copy link
Member Author

Choose a reason for hiding this comment

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

Copy link
Contributor

Choose a reason for hiding this comment

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

If this had not been static imported, I probably could have figured that out...

Copy link
Contributor

Choose a reason for hiding this comment

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

Also that's marked @InternalApi so it shouldn't be used here at all.

Copy link
Member Author

Choose a reason for hiding this comment

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

StorageException is also annotated with @InternalApi. I'm not introducing the use Error(). I think this is okay, as Storage isn't the only library using the base class BaseHttpServiceException, e.g. Bigquery.

Copy link
Collaborator

Choose a reason for hiding this comment

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

For @InternalApi from google-cloud-core, it's public because it needs to be, but intended for use by our libraries

Copy link
Contributor

Choose a reason for hiding this comment

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

I'll live with it this PR, but that's a major abuse of @InternalApi. It's as effectively locked in as any other public API. We should admit what's been done here, and remove @InternalApi from those classes. We can't change them absent an incompatible major version bump. :-(

@@ -73,4 +82,25 @@ public static StorageException translateAndThrow(RetryHelperException ex) {
BaseServiceException.translate(ex);
throw new StorageException(UNKNOWN_CODE, ex.getMessage(), ex.getCause());
}

/**
* Translate IOException to the StorageException that caused the error. This method default to
Copy link
Contributor

Choose a reason for hiding this comment

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

defaults


/**
* Translate IOException to the StorageException that caused the error. This method default to
* idempotent always being {@code True}. This method will force retry of the following transient
Copy link
Contributor

Choose a reason for hiding this comment

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

true? (primitive)
will force --> forces
or perhaps just will force retry of --> retries

/**
* Translate IOException to the StorageException that caused the error. This method default to
* idempotent always being {@code True}. This method will force retry of the following transient
* issues (Connection Closed Prematurely, Connection Reset).
Copy link
Contributor

Choose a reason for hiding this comment

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

"following" isn't needed; remove parentheses

* idempotent always being {@code True}. This method will force retry of the following transient
* issues (Connection Closed Prematurely, Connection Reset).
*
* <p>Please Review {@code RETRYABLE_ERRORS} for a full list of retryable errors.
Copy link
Contributor

Choose a reason for hiding this comment

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

rewrite without "please Review"
also, never use Please in technical docs per https://developers.google.com/style/tone

*
* <p>Please Review {@code RETRYABLE_ERRORS} for a full list of retryable errors.
*
* @throws StorageException when {@code ex} was caused by a {@code StorageException}
Copy link
Contributor

Choose a reason for hiding this comment

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

It returns, it doesn't throw

@frankyn
Copy link
Member Author

frankyn commented Mar 12, 2020

Thanks @elharo, I addressed your comments.

@frankyn frankyn requested a review from elharo March 12, 2020 16:18
@@ -43,7 +46,9 @@
new Error(500, null),
Copy link
Contributor

Choose a reason for hiding this comment

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

If this had not been static imported, I probably could have figured that out...

@@ -43,7 +46,9 @@
new Error(500, null),
Copy link
Contributor

Choose a reason for hiding this comment

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

Also that's marked @InternalApi so it shouldn't be used here at all.


/**
* Translate IOException to the StorageException that caused the error. This method defaults to
* idempotent always being {@code true}. This method retries the transient issues Connection
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't think it retries anything. There's no network connection here.

Copy link
Member Author

Choose a reason for hiding this comment

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

Ah,,, that's not worded well fixing.

@@ -73,4 +82,25 @@ public static StorageException translateAndThrow(RetryHelperException ex) {
BaseServiceException.translate(ex);
throw new StorageException(UNKNOWN_CODE, ex.getMessage(), ex.getCause());
}

/**
* Translate IOException to the StorageException that caused the error. This method defaults to
Copy link
Contributor

Choose a reason for hiding this comment

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

to the... --> to a StorageException representing the cause of the error. (otherwise you have the effect coming before the cause.)

* idempotent always being {@code true}. This method retries the transient issues Connection
* Closed Prematurely and Connection Reset.
*
* <p>Review {@code RETRYABLE_ERRORS} for a full list of retryable errors.
Copy link
Contributor

Choose a reason for hiding this comment

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

RETRYABLE_ERRORS is rightly private, but it won't show in API docs.

*
* @returns {@code StorageException}
*/
public static StorageException translate(IOException exception) {
Copy link
Contributor

Choose a reason for hiding this comment

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

translate is an uncommon name for this operation. Perhaps wrap?

Copy link
Member Author

Choose a reason for hiding this comment

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

Translate is what's being used in the code right now and wanted to keep consistent given there's already translateAndThrow

@frankyn frankyn requested a review from elharo March 12, 2020 18:23
@frankyn frankyn merged commit 27bccda into master Mar 13, 2020
@frankyn frankyn deleted the fix-premature-closure branch March 13, 2020 17:18
@frankyn
Copy link
Member Author

frankyn commented Mar 13, 2020

Merging after discussion with @elharo offline. Two approvals is more than enough for this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
cla: yes This human has signed the Contributor License Agreement.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Tracking bug: com.google.cloud.storage.StorageException: Connection closed prematurely:..
6 participants