Merge pull request #341 from izharahmd/retry-on-server-error

Retry publish on all 5XX errors
This commit is contained in:
eugene yokota 2020-09-29 10:33:33 -04:00 committed by GitHub
commit 949e1a6196
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 73 additions and 1 deletions

View File

@ -31,8 +31,14 @@ private[sbt] object IvyUtil {
}
}
/**
* Currently transient network errors are defined as:
* - a network timeout
* - all server errors (response code 5xx)
* - rate limiting (response code 429)
*/
object TransientNetworkException {
private val _r = """.*HTTP response code: (503|429).*""".r
private val _r = """.*HTTP response code: (5\d{2}|408|429).*""".r
@inline private def check(s: String): Boolean = {
if (s == null) return false

View File

@ -0,0 +1,66 @@
package sbt.internal.librarymanagement
import java.io.IOException
import org.scalatest.FunSuite
import sbt.internal.librarymanagement.IvyUtil._
class IvyUtilSpec extends FunSuite {
test("503 should be a TransientNetworkException") {
val statusCode503Exception =
new IOException("Server returned HTTP response code: 503 for URL:")
assert(TransientNetworkException(statusCode503Exception))
}
test("500 should be a TransientNetworkException") {
val statusCode500Exception =
new IOException("Server returned HTTP response code: 500 for URL:")
assert(TransientNetworkException(statusCode500Exception))
}
test("408 should be a TransientNetworkException") {
val statusCode408Exception =
new IOException("Server returned HTTP response code: 408 for URL:")
assert(TransientNetworkException(statusCode408Exception))
}
test("429 should be a TransientNetworkException") {
val statusCode429Exception =
new IOException(" Server returned HTTP response code: 429 for URL:")
assert(TransientNetworkException(statusCode429Exception))
}
test("404 should not be a TransientNetworkException") {
val statusCode404Exception =
new IOException("Server returned HTTP response code: 404 for URL:")
assert(!TransientNetworkException(statusCode404Exception))
}
test("IllegalArgumentException should not be a TransientNetworkException") {
val illegalArgumentException = new IllegalArgumentException()
assert(!TransientNetworkException(illegalArgumentException))
}
test("it should retry for 3 attempts") {
var i = 0
def f: Int = {
i += 1
if (i < 3) throw new RuntimeException() else i
}
// exception predicate retries on all exceptions for this test
val result = retryWithBackoff(f, _ => true, maxAttempts = 3)
assert(result == 3)
}
test("it should fail after maxAttempts") {
var i = 0
def f: Int = {
i += 1
throw new RuntimeException()
}
intercept[RuntimeException] {
retryWithBackoff(f, _ => true, maxAttempts = 3)
}
assert(i == 3)
}
}