During a maven publish if the server closes the TCP connection after the upload of an asset sometimes the publish will fail with a failed to respond while attempting to upload the checksum. The correct behavior to wanting to send more HTTP requests on a closed TCP connection, is to open a new TCP connection. If the client and server have a low latency connection, say in the same data center, when the connection is closed a new one appears to reliably be opened. During higher latency scenarios, in our case when the client and server are on different continents, maven attempts to reuse the connection that the server has already closed receiving a failed to respond error about half the time. On even slower connections we get a Connection or outbound has closed error.
Unfortunately, this connection does not get retried. It immediately fails to build no matter how many retries are configured. I believe this is the known https://issues.apache.org/jira/browse/MDEPLOY-162 If these requests were retried on this error, I suspect the entire situation would not have been a problem. The lack of retries go through different code paths depending on the transport implementation. The wagon transport fails with org.apache.maven.wagon.providers.http.httpclient.client.NonRepeatableRequestException: Cannot retry request with a non-repeatable request entity. Fixing the wagon transport requires changes in maven-wagon and in maven-resolver. In particular the WagonHttpEntity needs to use a stream supplier in order to be retryable. My colleague sketched out these changes a year ago. See https://github.com/mmarston/maven-wagon/commit/4419140ff7794a548f3f9cb9e320fcd20420b5e0 and https://github.com/mmarston/maven-resolver/commit/cf00080ac546bda588bd86a44f93c037f7638145 The native transport does not have this limitation because when uploading checksums it uses a PutTaskEntity that is retryable because the PutTask that it wraps around is essentially a stream supplier. Here<https://github.com/apache/maven-resolver/blob/89dadad860dc802fd328f2c7a29e7285b599ecde/maven-resolver-transport-http/src/main/java/org/eclipse/aether/transport/http/HttpTransporter.java#L635>. For the native transport my colleagues think the issue is that it only supports retry when the client detects the closed connection before or while sending the request. But if the client sends the request and then detects the closed connection while trying to read the response, then it won't retry. In particular the native transport uses DefaultHttpRequestRetryHandler with requestSentRetryEnabled set to false (see here<https://github.com/apache/maven-resolver/blob/d0f8564846863c8a88f2fb1da8391fc860517192/maven-resolver-transport-http/src/main/java/org/eclipse/aether/transport/http/HttpTransporter.java#L239>). One way to fix the native transport is to change requestSentRetryEnabled to true when constructing DefaultHttpRequestRetryHandler. Another option is to use StandardHttpRequestRetryHandler instead because it treats PUT requests as idempotent so will retry a PUT request even when requestSentRetryEnabled is false. Oddly, if only one checksum algorithm is selected by using -Daether.checksums.algorithms=MD5 then the entire build fails on this error but if two or more algorithms are selected -Daether.checksums.algorithms=MD5,SHA-1 each checksum throws a warning but the overall build succeeds. It seems odd that the behavior is inconsistent here. I would expect it either to always throw a warning if a requested checksum failed upload, or to always fail the build if any checksum failed upload. The behavior with multiple checksums requested makes it clear that this failed to respond error can be caught by mvn. Using -Daether.connector.http.reuseConnections=false makes this error go away, because maven never tries sending data over an existing TCP connection. I am new to the maven dev community and was not sure what the best practice was for reporting these kinds of issues. Starting a conversation on the mailing list seems like a good place to start. What should happen next? Which of these issues deserve tickets? What more information should I provide and where? What PRs would be appreciated to help fix the issues? A stack trace from running "mvn deploy" with Apache Maven 3.9.2 (c9616018c7a021c1c39be70fb2843d6f5f9b8a1c) org.apache.http.NoHttpResponseException: ...:443 failed to respond at org.apache.http.impl.conn.DefaultHttpResponseParser.parseHead (DefaultHttpResponseParser.java:141) at org.apache.http.impl.conn.DefaultHttpResponseParser.parseHead (DefaultHttpResponseParser.java:56) at org.apache.http.impl.io.AbstractMessageParser.parse (AbstractMessageParser.java:259) at org.apache.http.impl.DefaultBHttpClientConnection.receiveResponseHeader (DefaultBHttpClientConnection.java:163) at org.apache.http.impl.conn.CPoolProxy.receiveResponseHeader (CPoolProxy.java:157) at org.apache.http.protocol.HttpRequestExecutor.doReceiveResponse (HttpRequestExecutor.java:273) at org.apache.http.protocol.HttpRequestExecutor.execute (HttpRequestExecutor.java:125) at org.apache.http.impl.execchain.MainClientExec.execute (MainClientExec.java:272) at org.apache.http.impl.execchain.ProtocolExec.execute (ProtocolExec.java:186) at org.apache.http.impl.execchain.RetryExec.execute (RetryExec.java:89) at org.apache.http.impl.execchain.RedirectExec.execute (RedirectExec.java:110) at org.apache.http.impl.client.InternalHttpClient.doExecute (InternalHttpClient.java:185) at org.apache.http.impl.client.CloseableHttpClient.execute (CloseableHttpClient.java:72) at org.eclipse.aether.transport.http.HttpTransporter.execute (HttpTransporter.java:393) at org.eclipse.aether.transport.http.HttpTransporter.implPut (HttpTransporter.java:377) at org.eclipse.aether.spi.connector.transport.AbstractTransporter.put (AbstractTransporter.java:107) at org.eclipse.aether.connector.basic.BasicRepositoryConnector$PutTaskRunner.uploadChecksum (BasicRepositoryConnector.java:608) at org.eclipse.aether.connector.basic.BasicRepositoryConnector$PutTaskRunner.uploadChecksums (BasicRepositoryConnector.java:591) at org.eclipse.aether.connector.basic.BasicRepositoryConnector$PutTaskRunner.runTask (BasicRepositoryConnector.java:565) at org.eclipse.aether.connector.basic.BasicRepositoryConnector$TaskRunner.run (BasicRepositoryConnector.java:414) at org.eclipse.aether.connector.basic.BasicRepositoryConnector.put (BasicRepositoryConnector.java:319) at org.eclipse.aether.internal.impl.DefaultDeployer.deploy (DefaultDeployer.java:298) at org.eclipse.aether.internal.impl.DefaultDeployer.deploy (DefaultDeployer.java:201) at org.eclipse.aether.internal.impl.DefaultRepositorySystem.deploy (DefaultRepositorySystem.java:392) at org.apache.maven.plugins.deploy.AbstractDeployMojo.deploy (AbstractDeployMojo.java:139) at org.apache.maven.plugins.deploy.DeployMojo.execute (DeployMojo.java:191) at org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo (DefaultBuildPluginManager.java:126) at org.apache.maven.lifecycle.internal.MojoExecutor.doExecute2 (MojoExecutor.java:342) at org.apache.maven.lifecycle.internal.MojoExecutor.doExecute (MojoExecutor.java:330) at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:213) at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:175) at org.apache.maven.lifecycle.internal.MojoExecutor.access$000 (MojoExecutor.java:76) at org.apache.maven.lifecycle.internal.MojoExecutor$1.run (MojoExecutor.java:163) at org.apache.maven.plugin.DefaultMojosExecutionStrategy.execute (DefaultMojosExecutionStrategy.java:39) at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:160) at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject (LifecycleModuleBuilder.java:105) at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject (LifecycleModuleBuilder.java:73) at org.apache.maven.lifecycle.internal.builder.singlethreaded.SingleThreadedBuilder.build (SingleThreadedBuilder.java:53) at org.apache.maven.lifecycle.internal.LifecycleStarter.execute (LifecycleStarter.java:118) at org.apache.maven.DefaultMaven.doExecute (DefaultMaven.java:261) at org.apache.maven.DefaultMaven.doExecute (DefaultMaven.java:173) at org.apache.maven.DefaultMaven.execute (DefaultMaven.java:101) at org.apache.maven.cli.MavenCli.execute (MavenCli.java:910) at org.apache.maven.cli.MavenCli.doMain (MavenCli.java:283) at org.apache.maven.cli.MavenCli.main (MavenCli.java:206) at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0 (Native Method) at jdk.internal.reflect.NativeMethodAccessorImpl.invoke (NativeMethodAccessorImpl.java:62) at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke (DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke (Method.java:566) at org.codehaus.plexus.classworlds.launcher.Launcher.launchEnhanced (Launcher.java:283) at org.codehaus.plexus.classworlds.launcher.Launcher.launch (Launcher.java:226) at org.codehaus.plexus.classworlds.launcher.Launcher.mainWithExitCode (Launcher.java:407) at org.codehaus.plexus.classworlds.launcher.Launcher.main (Launcher.java:348)