At the core of ZIO is
ZIO: an effect type used to describe side effects in a simple, type-safe, testable and composable way.
ZIO[-R, +E, +A] has three type parameters:
R: represents an environment of type
R. If this type parameter is
Any, it means the effect has no requirements because it can be an
(). Example values are
- Database connection, repository
- Web Service, logging service
- Application context, clock, random generator
- Configuration, session data
E: a failure type representing a faile of type
E. Often it is
Throwable. If the type is
Nothing, it means the effect cannot fail because there is no value of type
Nothing. Example values are
A: a success type of
A. If it is
Unit, it means that the program is side-effect-only program that produces no useful information. If it is
Nothing, it means the program runs forever or until it fails.
ZIO[R, E, A] must have an
A type, the
E are optional. There are three possible aliases:
ZIO[Any, Nothing, A], an effect has no requirements and cannot fail.
URIO[R, A]: is
ZIO[R, Nothing, A], an effect has requirments but cannot faile.
IO[E, A]: is
ZIO[Any, E, A], an effect has no requirements.
There are two aliase if
ZIO[Any, Throwable, A], no requirements, can throw.
RIO[R, A]: is
ZIO[R, Throwable, A], has requirements, can throw.
Therefore there are total six types:
ZIO[R, E, A],
RIO[R, A] because
R can be
E can be
Throable. Each type defines methods to create values of the type.
Task is similar to
Future that can throw or return data.
UIO represents an infallible effects, including those resulting from handling all errors.
ZIO.succeedmethod creates an succss effect. The method is eager, which means the parameter is evaluated before the method is invoked. The result is of type
ZIO.effectTotalis a lazy mehtod. The result is of type
ZIO.failcreates a failure effect of type
ZIO.fromOptioncreates a success effect of type
Some[A], a failure effect of type
Trycan only fail with values of type
R => Areturns a
A synchronous side-effect can be converted into a ZIO effect using
ZIO.effect, for example,
val getStrinLn: Task[String] = ZIO.effect(scala.io.StdIn.readLine()). Like Future, side-effect only throw exceptions. If a side-effect doesn’t throw any exception, use
ZIO.effectTotal, for example
def putStrLn(line: String): UIO[Unit] = ZIO.effectTotal(println(line)).
An asynchronous side-effect with a callback-based API can be converted into a ZIO effect using
ZIO.effectAsync method. It returns a value of type
IO[E, A] that has features such as interruption, resource-safety and good error-handling.
zio.blocking package for blocking IO. The
effectBlock(Thread.sleep(10)) will be executed on a separate thread pool. Use
effectBlockingCancelable for cancelable side-effects. The
blocking method is used to run ZIO effect in the blocking thread pool.
A ZIO effect provides many methods to process data or compose more effects.
map: transform success value. The shortcut for this is
mapErrorCause: transform failure value.
orElse: use an other effect when the first fails.
fold: handles both failure and success results.
catchAllCause: handle all errors.
flatMap: the result of the first effect is the input of the second effect. When the first effect fails, the
forexpression: chain multiple effects using
zip: the first executes first, then the second, the results are zipped into a tuple. If either fails, the cmposed effect fails.
*>, only keep the right.
<*, only keep the left.
ZIO provides full stack trace of errors. It gives the location of error, the next statement to be executed and many other useful informaiton.
You can surface failure with
either that takes an
ZIO[R, E, A] to
ZIO[R, Nothing, Eiterh[E, A]]. The result is the same as
URIO[R, Either[E, A]]. You can submerge failures with
ZIO.absovle that transform an
URIO[R, Either[E, A]] into
ZIO[R, E, A].
catchAll to recover from all types of errors. Use
catchSome with a partial function to recover from some types of errors. Both cannot rececude or eliminate the error type, they can wide the error type to a subtype. Use
orElse to try another effect when the first fails.
fold method lets you define non-effectful handler for failure and success. The
foldM method lets your handle both in a effectful way.
retry method teaks a
Schedule and returns a new effect that will retry the first effect if it fails.
retryOrElse allows both retry and, if all retries fail, try another effect.
retryOrElseEither allows returning a differen type for the fallback.
ZIO’s resource management provides guarantees in the presence of failure, interruption or defects in the application.
ensuring(finalizer) guarantees that if an effect terminates for whatever reason, the finalizer will begin executing. The finalizer has a type of
UIO[A] and is not allowed to fail. It must handle all errors internally.
ensuring works across all types of effects, including asynchronous and concurrent effects.
bracket method takes a release effect and a use effect. It guarantees to run to run the release effect, even in the presence of errors or interruption.
ZIO provides concurrency via fibers. Fibers are low level. ZIO provides high-level operations built on fibers.
ZIO fibers consume almost no memory, have growable and shrinkable stacks, don’t waste resources blocking, and will be garbage collected automatically if they are suspended and unreachable.
Fibers are created and scheduled by ZIO runtime and cooperatively yield to each other. All effects are executed by some fibers. A fiber type
Fiber[E, A] models an effect that is running.
E is the failure type and
A is the success value. A fiber represents a handle on the running computaiton.
fork method creates a new fiber and execute the effect on this new fiber. The
Fiber#join returns an effect.
Fiber#await returns an effect containing an
Exit value that provides full information on how the fiber completed.
Fiber#interrupt intterrupts the fiber and returns an
Exit. by design, the effect returned by
Fiber#interrupt does not resume until the fiber has completed. If this is not desired, you can
fork the interruption as
Fiber#zipWith compose fibers. The
Fiber.orElse runs the second fiber if the first fails.
ZIO provides parallel operations. These methods are named with a
Par suffix. For example,
mergeAllPar. If one fails, the others will be interrupted. If this is undesired, convert fallible effects into infallible effects using the
For first success, use
fiber1 race fiber2. If the first success or failure, use
fiber1.either race fiber2.either.
ZIO#timeout method covnerts an effect into
Option[A]. When it completes within the timeout, the result is
For a greenfield project, extends
zio.APP and define
def run(args: List[String]): ZIO[ZEnv, Nothing, Int]. The
type ZEnv = Clock with Console with System with Random with Blocking is a resource that is provided by the default runtime:
zio.Runtime.default. It can run effects that require any combination of these modules. The following is a simple application:
An other way to use the default runtime is to use it to run logics directly without using
zio.App. Foe example:
A custom runtime
Runtime[R] can be created with two values:
Platform: to bootstrap the runtime system
Platform has an error report that can be customized. The default is to log the error to standard error.
Ref and STM
Ref allows atomic get/set/update/modify. STM allows multiple operations and multiple Refs in a transaction. The
TRef#collect mathod has built-in automatic retry. All operations are asynchronous and non-blocking.