Skip to content

Properly close the Apache response so that connections can be reused #3861

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 2 commits into from
Oct 30, 2018

Conversation

agherardi
Copy link
Contributor

@agherardi
Copy link
Contributor Author

agherardi commented Jun 17, 2018

Not sure why the ip-validation check is failing. I entered my email address on https://accounts.eclipse.org/users/agherardi/eca, the tool says "There is a valid ECA on file for my-email-address".

Also, not sure why the CI build fails, when running travis.sh -Ptravis_e2e all test pass on my desktop.

@chkal
Copy link
Contributor

chkal commented Jun 18, 2018

@agherardi You have to "sign off" your commits using the -s option of Git. This will add a special line to your commit message. See the Eclipse Foundation documentation for details:

https://wiki.eclipse.org/Development_Resources/Contributing_via_Git#Signing_off_on_a_commit

@agherardi agherardi force-pushed the properlyClose branch 3 times, most recently from 5a04aca to 55d9efa Compare June 18, 2018 14:49
@jansupol
Copy link
Contributor

Fixes #3629

@agherardi
Copy link
Contributor Author

Hi - Any updates?

@jansupol
Copy link
Contributor

Sorry it takes long. I want to verify regarding the #3629.

Comment on lines +622 to +628
try {
super.close();
} catch (IOException ex) {
// Ignore
} finally {
response.close();
}
Copy link

@isopropylcyanide isopropylcyanide Aug 6, 2020

Choose a reason for hiding this comment

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

Thanks @agherardi for fixing this

2 years down the line and because of a missing response.close() in previous versions of Jersey in a finally block, the pooled http connection was never released.

Our leased http connections never were returned to the pool because response wasn't being explicitly read into entities in some cases.

Our request threads talked to a database and had written few rows (REPEATABLE_READ). As a result, the JDBI handle was never closed (thread was in PARKED state due to no more available connections in the pool) and exclusive locks were held as the request was neither rolled back nor committed but suspended.

We have finally figured out the root cause. Thank you.

Copy link
Contributor

Choose a reason for hiding this comment

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

Please understand that this also depends on the Apache HTTP Client version. See also a followup discussion.

@chriskessel
Copy link

chriskessel commented Oct 23, 2020

I'm unable to upgrade past Jersey 2.25.1 since 2.26 and beyond are breaking changes with Dropwizard 1.3 (some hk2/guice thing, I think). Yes, I want to upgrade Dropwizard, but that's a large task.

Is there a hack/workaround I can use to fix this without upgrading? Some way of closing connections/responses or setting timeout properties?

I'm hitting this pretty regularly in a ForkJoinPool that does 10 parallel requests and eventually the http client just stops working and timing out every time on my Future.get().

@jansupol
Copy link
Contributor

Since 2.26 you need additional Jersey dependency:
org.glassfish.jersey.inject:jersey-hk2
Does it help?

@chriskessel
Copy link

Unfortunately, no. I can't upgrade to 2.26 because there's a breaking dependency with adding hk2. It has a race condition with Dropwizard 1.x (1.3) related to something with a module to use Guice. I spent most of the last 2 days trying to get Jersey (2.32 I think) working, chasing never ending dependency issues, but could never get past some service provider race condition at startup. Nor could I get around a conflicting dependency between hibernate-validators and hibernate-validators-spi (I think it's those two), declaring the same package, that came as a result of those attempted upgrades 👍

Hence, my wondering if there is a workaround or a way to use the 2.25 such that this connection hang/leak won't occur?

@isopropylcyanide
Copy link

@chriskessel If you ensure that the inbound JAX-RS response is always closed, you'll never face a leak. Because the response isn't closed, the HTTP connection you've leased from the pool will not be returned back as the response associated with it hasn't been used yet. If Apache devs return the connection blindly and you try to read the response later, it's going to be a problem (response has been already closed)

. If you consume entities from only 2xx responses, response will be properly closed since reading off of the inputstream closes the entity as well.

Two options

  • Always close the JAX-RS response (in a finally block)
  • Always read the entity from a response.

The first one should be preferred. Use an Instrumented Http Connection Pool. Plot metrics of each pool. Monitor the pool leased allocation rate against the leased total rate. You should be good.

@chriskessel
Copy link

chriskessel commented Oct 27, 2020

Always close the JAX-RS response (in a finally block)

Unfortunately, I already do that and it still has the issue. I use a little lombok delegate wrapper I created.

@Value
class ClosableResponse extends Response implements AutoCloseable {
        @Delegate
        Response original;
    }

Then all usages look like:

  try (ClosableResponse response = new ClosableResponse(httpClient.target(uri)
                .request(MediaType.APPLICATION_XML)
                .get(Response.class))) {
            ...do stuff here...
        }

I suppose I could add an entity read just before the close out of paranoia?

@jansupol
Copy link
Contributor

Response is AutoClosable in JAX-RS 2.1 (Jersey 2.26+ dependency). Apache connector supports ClientProperties.READ_TIMEOUT and ClientProperties.CONNECT_TIMEOUT.

@chriskessel
Copy link

@jansupol Good to know! Though, as I noted, I can't move past 2.25.1 without upgrading other libraries (including the main framework we use).

I have added those timeouts, maybe that will help.

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.

6 participants