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

Optimize connection close logic to resolve timeout delay issue #508

Merged
merged 7 commits into from
Nov 28, 2024

Conversation

ooeunz
Copy link
Contributor

@ooeunz ooeunz commented Nov 27, 2024

Description

  • Introduced a configuration option useRstOnTimeout in Http1Config to allow connections to be closed with an RST (Reset) signal when a timeout occurs.
  • Updated HttpRequestExecutor to respect this configuration and invoke the appropriate close mode (CloseMode.IMMEDIATE for RST or Closer.closeQuietly for FIN).
  • Maintained backward compatibility by defaulting to FIN-based connection closure.

This change improves flexibility and allows faster resource cleanup in timeout scenarios, aligning with the HTTP/1.1 recommendations for abnormal connection termination.

Problem Description

There is an issue where the connection close operation takes as long as the SocketTimeout value set in the SocketConfig after a Socket timeout occurs. This behavior arises because the NioSocketImpl performs an additional poll for the duration of the SocketTimeout during the close operation. Consequently, HTTP requests may experience delays of up to twice the configured SocketTimeout value.

Proposed Solution

This Pull Request introduces the useRstOnTimeout configuration option to mitigate this issue by enabling connections to be closed using an RST signal instead of a FIN-based closure.

  • Key benefits:
    • Avoids unnecessary delays during connection closure.
    • Ensures efficient resource cleanup.
    • Maintains backward compatibility by defaulting to FIN-based closure.

The following image shows the test results with the socket timeout value set to 5 seconds
img-1

img-2

Example Workflow Before Fix

  1. Socket timeout occurs:
    The socket reaches the timeout value specified in the SocketTimeout configuration.
  2. Connection close:
    During the close operation, the NioSocketImpl performs an additional poll for the same timeout duration.
  3. Total wait time:
    HTTP requests may end up waiting for up to twice the configured SocketTimeout value.

Resolves: HTTPCLIENT-2324

- Introduced a configuration option `useRstOnTimeout` in `Http1Config`
  to allow connections to be closed with an RST (Reset) signal when
  a timeout occurs.
- Updated `HttpRequestExecutor` to respect this configuration and
  invoke the appropriate close mode (`CloseMode.IMMEDIATE` for RST
  or `Closer.closeQuietly` for FIN).
- Maintained backward compatibility by defaulting to FIN-based
  connection closure.

This change improves flexibility and allows faster resource
cleanup in timeout scenarios, aligning with the HTTP/1.1
recommendations for abnormal connection termination.

Resolves: HTTPCLIENT-2324
Copy link
Member

@ok2c ok2c left a comment

Choose a reason for hiding this comment

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

@@ -109,6 +111,10 @@ public int getInitialWindowSize() {
return initialWindowSize;
}

public boolean getUseRstOnTimeout() {
Copy link
Member

Choose a reason for hiding this comment

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

@ooeunz Please add @since 5.4 tag

@@ -222,6 +232,11 @@ public Builder setInitialWindowSize(final int initialWindowSize) {
return this;
}

public Builder setUserRstOnTimeout(final boolean userRstOnTimeout) {
Copy link
Member

Choose a reason for hiding this comment

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

@ooeunz Please add @since 5.4 tag

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added. Thanks.

Copy link
Member

@garydgregory garydgregory left a comment

Choose a reason for hiding this comment

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

Hello @ooeunz

See my comments.

Is it possible to write a test that shows the new code does anything?

@@ -222,6 +235,14 @@ public Builder setInitialWindowSize(final int initialWindowSize) {
return this;
}

/**
* @since 5.4
Copy link
Member

Choose a reason for hiding this comment

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

I think you need a real Javadoc description that explains what this toggle does.

@@ -212,7 +213,11 @@ public ClassicHttpResponse execute(
return response;

} catch (final HttpException | IOException | RuntimeException ex) {
Closer.closeQuietly(conn);
if (http1Config.getUseRstOnTimeout()) {
Copy link
Member

Choose a reason for hiding this comment

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

Is there a use case for keeping the old behavior?

Copy link
Member

Choose a reason for hiding this comment

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

@garydgregory Graceful shutdown of TLS connections would be one. One can drop a TLS connection without a close-notify handshake but it is generally considered rude.

@ooeunz Why do not we always use IMMEDIATE close for plain (non TLS) conections by default? Would that make the new config flag redundant?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

To maintain backward compatibility, the existing behavior has been preserved.

However, if it is determined that there are no issues with backward compatibility, I would like to make immediate close the default behavior.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think that a socket timeout indicates that the server is not functioning properly, so setting immediate close as the default behavior should not cause any issues.

Copy link
Member

Choose a reason for hiding this comment

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

TY @ok2c for the explanation. I think details like this should be in the Javadoc for the getter-setter pair.

@ok2c
Copy link
Member

ok2c commented Nov 27, 2024

@ooeunz Almost there. Please fix the style check violations and update the title of PR and will merge the change-set.

@ooeunz ooeunz changed the title Introduce useRstOnTimeout to address extended close times after SocketTimeout Optimize connection close logic to resolve timeout delay issue Nov 27, 2024
@ooeunz
Copy link
Contributor Author

ooeunz commented Nov 28, 2024

@ok2c @garydgregory I’ve completed refining the code style. It was such an enjoyable experience to collaborate and build the code together! 😊

@ok2c ok2c merged commit 8ee6483 into apache:master Nov 28, 2024
10 checks passed
@ok2c
Copy link
Member

ok2c commented Nov 28, 2024

@ooeunz Cherry-picked to 5.3.x

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants