[ 
https://issues.apache.org/jira/browse/WAGON-486?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=15956729#comment-15956729
 ] 

Michael Osipov edited comment on WAGON-486 at 4/5/17 1:57 PM:
--------------------------------------------------------------

OK, great. Let me clarify first why I do think that client and server behave 
correctly though I have not seen a Wireshark capture (can you provide one from 
the client side?):

[RFC 7230, Section 6.5|https://tools.ietf.org/html/rfc7230#section-6.5] says:

{quote}
   A client or server that wishes to time out SHOULD issue a graceful
   close on the connection.  Implementations SHOULD constantly monitor
   open connections for a received closure signal and respond to it as
   appropriate, since prompt closure of both sides of a connection
   enables allocated system resources to be reclaimed.

   A client, server, or proxy MAY close the transport connection at any
   time.  For example, a client might have started to send a new request
   at the same time that the server has decided to close the "idle"
   connection.  From the server's point of view, the connection is being
   closed while it was idle, but from the client's point of view, a
   request is in progress.
{quote}

and now the answer to that from the [Apache HttpClient, Chapter 
2.5|https://hc.apache.org/httpcomponents-client-ga/tutorial/html/connmgmt.html#d5e418]:

{quote}
One of the major shortcomings of the classic blocking I/O model is that the 
network socket can react to I/O events only when blocked in an I/O operation. 
When a connection is released back to the manager, it can be kept alive however 
it is unable to monitor the status of the socket and react to any I/O events. 
If the connection gets closed on the server side, the client side connection is 
unable to detect the change in the connection state (and react appropriately by 
closing the socket on its end).
{quote}

So the NAT closes the connection, but our client cannot detect that due to 
blocking I/O, it first fails with the next request.

There are basically two ways to solve that with HttpClient:

1. Set an upper TTL for all connections at construction time
2. Spawn an evictor thread which probes connection in the background

I have chosen to go with 1. Why? While 2 is directly supported by HttpClient, 
Wagon's code is structured in a way that it does not close the HttpClient 
(leakage), but this is absolutely required to shutdown the thread properly.
The first one is pretty cheap as it compares timestamps during 
{{leaseConnection}} only.

This is what I did:

{noformat}
diff --git 
a/wagon-providers/wagon-http/src/main/java/org/apache/maven/wagon/providers/http/AbstractHttpClientWagon.java
 
b/wagon-providers/wagon-http/src/main/java/org/apache/maven/wagon/providers/http/AbstractHttpClientWagon.java
old mode 100755
new mode 100644
index 405f55e..8075c69
--- 
a/wagon-providers/wagon-http/src/main/java/org/apache/maven/wagon/providers/http/AbstractHttpClientWagon.java
+++ 
b/wagon-providers/wagon-http/src/main/java/org/apache/maven/wagon/providers/http/AbstractHttpClientWagon.java
@@ -355,7 +355,7 @@
                                                                                
                                  PlainConnectionSocketFactory.INSTANCE 
).register(
             "https", sslConnectionSocketFactory ).build();
 
-        PoolingHttpClientConnectionManager connManager = new 
PoolingHttpClientConnectionManager( registry );
+        PoolingHttpClientConnectionManager connManager = new 
PoolingHttpClientConnectionManager( registry, null, null, null, 3L, 
TimeUnit.MINUTES  );
         if ( persistentPool )
         {
             connManager.setDefaultMaxPerRoute( MAX_CONN_PER_ROUTE );
{noformat}

Beware that this check only happens when {{leaseConnection}} is called and not 
after three minutes.

So the question is how we can implement this best?


was (Author: michael-o):
OK, great. Let me clarify first why I do think that client and server behave 
correctly though I have not seen a Wireshark capture (can you provide one from 
the client side?):

[RFC 7230, Section 6.5|https://tools.ietf.org/html/rfc7230#section-6.5] says:

{quote}
   A client or server that wishes to time out SHOULD issue a graceful
   close on the connection.  Implementations SHOULD constantly monitor
   open connections for a received closure signal and respond to it as
   appropriate, since prompt closure of both sides of a connection
   enables allocated system resources to be reclaimed.

   A client, server, or proxy MAY close the transport connection at any
   time.  For example, a client might have started to send a new request
   at the same time that the server has decided to close the "idle"
   connection.  From the server's point of view, the connection is being
   closed while it was idle, but from the client's point of view, a
   request is in progress.
{quote}

and now the answer to that from the [Apache HttpClient, Chapter 
2.5|https://hc.apache.org/httpcomponents-client-ga/tutorial/html/connmgmt.html#d5e418]:

{quote}
One of the major shortcomings of the classic blocking I/O model is that the 
network socket can react to I/O events only when blocked in an I/O operation. 
When a connection is released back to the manager, it can be kept alive however 
it is unable to monitor the status of the socket and react to any I/O events. 
If the connection gets closed on the server side, the client side connection is 
unable to detect the change in the connection state (and react appropriately by 
closing the socket on its end).
{quote}

So the NAT closes the connection, but our client cannot detect that due to 
blocking I/O, it first fails with the next request.

There are basically two ways to solve that with HttpClient:

1. Set an upper TTL for all connections at construction time
2. Spawn an evictor thread which probes connection in the background

I have chosen to go with 1. Why? While 2 is directly supported by HttpClient, 
Wagon's code is structured in a way that it does not close the HttpClient 
(leakage), but this is absolutely required to shutdown the thread properly.
The first one is pretty cheap as it compares timestamps during 
{{leastConnection}} only.

This is what I did:

{noformat}
diff --git 
a/wagon-providers/wagon-http/src/main/java/org/apache/maven/wagon/providers/http/AbstractHttpClientWagon.java
 
b/wagon-providers/wagon-http/src/main/java/org/apache/maven/wagon/providers/http/AbstractHttpClientWagon.java
old mode 100755
new mode 100644
index 405f55e..8075c69
--- 
a/wagon-providers/wagon-http/src/main/java/org/apache/maven/wagon/providers/http/AbstractHttpClientWagon.java
+++ 
b/wagon-providers/wagon-http/src/main/java/org/apache/maven/wagon/providers/http/AbstractHttpClientWagon.java
@@ -355,7 +355,7 @@
                                                                                
                                  PlainConnectionSocketFactory.INSTANCE 
).register(
             "https", sslConnectionSocketFactory ).build();
 
-        PoolingHttpClientConnectionManager connManager = new 
PoolingHttpClientConnectionManager( registry );
+        PoolingHttpClientConnectionManager connManager = new 
PoolingHttpClientConnectionManager( registry, null, null, null, 3L, 
TimeUnit.MINUTES  );
         if ( persistentPool )
         {
             connManager.setDefaultMaxPerRoute( MAX_CONN_PER_ROUTE );
{noformat}

Beware that this check only happens when {{leaseConnection}} is called and not 
after three minutes.

So the question is how we can implement this best?

> Maven does not attempt to reconnect reset connections
> -----------------------------------------------------
>
>                 Key: WAGON-486
>                 URL: https://issues.apache.org/jira/browse/WAGON-486
>             Project: Maven Wagon
>          Issue Type: Bug
>            Reporter: Martin MyslĂ­k
>         Attachments: build-failure-maven-3.5.0-patched-debug.txt, 
> build-failure-maven-3.5.0-patched-debug-updated.txt, 
> build-failure-vanilla.txt, build-success-keep-alive-false.txt, 
> build-success-maven-3.5.0-patched-debug.txt, build-success-pooling-false.txt
>
>
> I was recently discussing and issue with Atlassian team concerning failing 
> build on Atlassian Pipelines when running Maven build for more than 5 minutes.
> The issue was with NAT timeout which kills all idle connections after 5 
> mintues and Maven does not try to reconnect once the connection is killed 
> (and hence cannot download artifacts from Maven central).
> Please, take a look at the open issue (it contains more detailed description 
> and also comments from Atlassian which suggested opening an issue with 
> Maven): 
> https://bitbucket.org/site/master/issues/13988/pipelines-kills-idle-maven-connections
> Could you, please, take a minute and explain how could proceed with solving 
> this issue? I am not sure whether this is something that Maven should handle 
> or whether it is Atlassians issue.
> Thank you for your input. 
> This is the link to my public repo with test project running tests for 15 
> mintues. This build fails on Pipelines because of Maven connection that is 
> being killed during the test: https://bitbucket.org/Smedzlatko/del-me



--
This message was sent by Atlassian JIRA
(v6.3.15#6346)

Reply via email to