Rezilience
rezilience
is a ZIO-native collection of policies for making asynchronous systems more resilient to failures, inspired by Polly, Resilience4J and Akka.
It consists of these policies:
Policy | Reactive/Proactive | Description |
---|---|---|
CircuitBreaker | Reactive | Temporarily prevent trying calls after too many failures |
RateLimiter | Proactive | Limit the rate of calls to a system |
Bulkhead | Proactive | Limit the number of in-flight calls to a system |
Retry | Reactive | Try again after transient failures |
Timeout | Reactive | Interrupt execution if a call does not complete in time |
Features / Design goals
- Type-safety: all errors that can result from any of the
rezilience
policies are encoded in the method signatures, so no unexpected RuntimeExceptions. - Support for your own error types (the
E
inZIO[R, E, A]
) instead of requiring your effects to haveException
as error type - Lightweight:
rezilience
uses only ZIO fibers and will not create threads or block - Switchable at runtime with two transition modes
- Resource-safe: built on ZIO’s
ZManaged
, any allocated resources are cleaned up safely after use. - Interrupt safe: interruptions of effects wrapped by
rezilience
policies are handled properly. - Thread-safe: all policies are safe under concurrent use.
- ZIO integration: some policies take for example ZIO
Schedule
s andrezilience
tries to help type inference using variance annotations - Metrics: all policies (will) provide usage metrics for monitoring purposes
- Composable: policies can be composed into one overall policy
- Discoverable: no syntax extensions or implicit conversions, just plain scala
Installation
Add to your build.sbt:
libraryDependencies += "nl.vroste" %% "rezilience" % "<version>"
Rezilience is available for ZIO 2 and Scala 2.13, Scala 3 and Scala.JS.
Usage example
Limit the rate of calls:
import zio._
import zio.duration._
import nl.vroste.rezilience._
def myCallToExternalResource(someInput: String): ZIO[Any, Throwable, Int] = ???
val rateLimiter: ZIO[Scope, Nothing, RateLimiter] = RateLimiter.make(max = 10, interval = 1.second)
ZIO.scoped {
rateLimiter.flatMap { rateLimiter =>
val result: ZIO[Any, Throwable, Int] =
rateLimiter(myCallToExternalResource("some input"))
}
}