Skip to content

Commit ca4980c

Browse files
authored
airframe-http: Retry on Finagle's ChannelClosedException (#1089)
1 parent 2b77ad5 commit ca4980c

File tree

1 file changed

+19
-5
lines changed

1 file changed

+19
-5
lines changed

airframe-http/src/main/scala/wvlet/airframe/http/HttpClientException.scala

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,15 @@ package wvlet.airframe.http
1515
import java.io.{EOFException, IOException}
1616
import java.lang.reflect.InvocationTargetException
1717
import java.net._
18+
import java.nio.channels.ClosedChannelException
1819
import java.util.concurrent.{ExecutionException, TimeoutException}
1920

2021
import javax.net.ssl.{SSLException, SSLHandshakeException, SSLKeyException, SSLPeerUnverifiedException}
2122
import wvlet.airframe.control.ResultClass
2223
import wvlet.airframe.control.ResultClass.{Failed, Succeeded, nonRetryableFailure, retryableFailure}
2324
import wvlet.airframe.control.Retry.RetryContext
2425
import wvlet.log.LogSupport
26+
2527
import scala.language.existentials
2628

2729
/**
@@ -120,7 +122,9 @@ object HttpClientException extends LogSupport {
120122
"Idle connections will be closed".r
121123
)
122124

123-
retriable400ErrorMessage.find { pattern => pattern.findFirstIn(m).isDefined }.isDefined
125+
retriable400ErrorMessage.find { pattern =>
126+
pattern.findFirstIn(m).isDefined
127+
}.isDefined
124128
}
125129

126130
/**
@@ -164,10 +168,11 @@ object HttpClientException extends LogSupport {
164168
case e: java.lang.InterruptedException =>
165169
// Retryable when the http client thread execution is interrupted.
166170
retryableFailure(e)
167-
case e: ProtocolException => retryableFailure(e)
168-
case e: ConnectException => retryableFailure(e)
169-
case e: EOFException => retryableFailure(e)
170-
case e: TimeoutException => retryableFailure(e)
171+
case e: ProtocolException => retryableFailure(e)
172+
case e: ConnectException => retryableFailure(e)
173+
case e: EOFException => retryableFailure(e)
174+
case e: TimeoutException => retryableFailure(e)
175+
case e: ClosedChannelException => retryableFailure(e)
171176
case e: SocketException =>
172177
e match {
173178
case se: BindException => retryableFailure(e)
@@ -177,8 +182,17 @@ object HttpClientException extends LogSupport {
177182
case other =>
178183
nonRetryableFailure(e)
179184
}
185+
// Exceptions from Finagle. Using the string class names so as not to include Finagle dependencies.
186+
case e: Throwable if finagleRetryableExceptionClasses.contains(e.getClass().getName) =>
187+
retryableFailure(e)
180188
}
181189

190+
private[http] val finagleRetryableExceptionClasses = Set(
191+
"com.twitter.finagle.ChannelClosedException",
192+
"com.twitter.finagle.ReadTimedOutException",
193+
"com.twitter.finagle.WriteTimedOutException"
194+
)
195+
182196
def sslExceptionClassifier: PartialFunction[Throwable, Failed] = {
183197
case e: SSLException =>
184198
e match {

0 commit comments

Comments
 (0)