Failurewall
This is a library to protect applications against failures, and helpful in developing stable, responsive and resilient systems.
Failurewall is inspired by Hystrix and adapted for scala.concurrent.Future
.
Getting Started
You should add the following dependency.
libraryDependencies += "com.okumin" %% "failurewall-core" % "0.4.0"
If you are using Akka 2.4, you can use failurewall-akka
. failurewall-akka
provides the following failurewalls.
- circuit breaker
- retry with backoff
- timeout
libraryDependencies += "com.okumin" %% "failurewall-akka" % "0.4.0"
If you are using Akka 2.3, see also failurewall-akka23.
How to use
As a Proxy
Failurewall is simple to use, wrapping scala.concurrent.Future
to be protected. Each failurewall has abilities to handle failures.
object HttpClient {
def get(url: String): Future[Response] = ???
}
val wall: Failurewall[Response, Response] = ???
val response: Future[Response] = wall.call(HttpClient.get("http://okumin.com/"))
Composability
Failurewalls has their own ability, e.g. retrying, checking rate limits and throttling. Failurewall#compose
makes Failurewalls decorate such features.
val wallSina: Failurewall[Int, String] = ???
val wallRose: Failurewall[Int, Int] = ???
val wallMaria: Failurewall[Double, Int] = ???
val walls: [Double, String] = wallSina compose wallRose compose wallMaria
Built-in walls(failurewall-core)
RetryFailurewall
Retries on temporary failures.
val wall = RetryFailurewall[Response](10, executionContext)
wall.call(Future.failed(new RuntimeException)) // retry 10 times
StdSemaphoreFailurewall
Keeps resource usage constant.
val wall = StdSemaphoreFailurewall[Response](10, executionContext)
val results = (1 to 100).map { _ =>
// fails immediately while other 10 calls are running
wall.call(doSomeOperation())
}
StopwatchFailurewall
Measures the execution time.
val wall = StopwatchFailurewall[Response](executionContext)
wall.call(doSomeOperation()) // returns Future[(Try[Response], FiniteDuration)]
Built-in walls(failurewall-akka)
AkkaCircuitBreakerFailurewall
Prevents a failure from leading to cascading other failures.
// has a little complicated constructor
val wall: AkkaCircuitBreakerFailurewall[Response] = ???
val results = (1 to 100).map { _ =>
// fail-fast after failure times exceeds the threshold
wall.call(Future {
throw new RuntimeException
})
}
AkkaRetryFailurewall
Retries with backoff on temporary failures.
val backoffStrategy = ExponentialBackoffStrategy(
minBackoff = 100.millis,
maxBackoff = 10.seconds,
multiplier = 2.0
)
val wall = AkkaRetryFailurewall[Response](
10,
backoffStrategy,
akkaScheduler,
executionContext
)
// retry 10 times with exponential backoff
wall.call(Future.failed(new RuntimeException))
AkkaTimeoutFailurewall
Times out when it takes some duration.
val wall = AkkaTimeoutFailurewall[String](5.seconds, akkaScheduler, executionContext) {
logger.error("Timed out.")
}
// fails with FailurewallException
wall.call(Future {
Thread.sleep(10000)
"mofu"
})