Lifecycle

izumi.functional.lifecycle.Lifecycle
See theLifecycle companion object
trait Lifecycle[+F[_], +A]

Lifecycle is a class that describes the effectful allocation of a resource and its finalizer. This can be used to represent expensive resources.

Resources can be created using Lifecycle.make:

 def open(file: File): Lifecycle[IO, BufferedReader] =
   Lifecycle.make(
     acquire = IO { new BufferedReader(new FileReader(file)) }
   )(release = reader => IO { reader.close() })

Using inheritance from Lifecycle.Basic:

 final class BufferedReaderResource(
   file: File
 ) extends Lifecycle.Basic[IO, BufferedReader] {
   def acquire: IO[BufferedReader] = IO { new BufferedReader(new FileReader(file)) }
   def release(reader: BufferedReader): IO[BufferedReader] = IO { reader.close() }
 }

Using constructor-based inheritance from Lifecycle.Make, Lifecycle.LiftF, etc:

 final class BufferedReaderResource(
   file: File
 ) extends Lifecycle.Make[IO, BufferedReader](
   acquire = IO { new BufferedReader(new FileReader(file)) },
   release = reader => IO { reader.close() },
 )

Or by converting from an existing cats.effect.Resource, scoped zio.ZIO or a zio.managed.ZManaged:

Usage is done via use:

 open(file1).use {
   reader1 =>
     open(file2).use {
       reader2 =>
         readFiles(reader1, reader2)
     }
 }

Lifecycles can be combined into larger Lifecycles via Lifecycle#flatMap (and the associated for-comprehension syntax):

val res: Lifecycle[IO, (BufferedReader, BufferedReader)] = {
  for {
    reader1  IO(println("Disconnecting DB")))
 val mqResource = Lifecycle.make(IO { println("Connecting to Message Queue!"); new MessageQueueConnection })(_ => IO(println("Disconnecting Message Queue")))

 class MyApp(db: DBConnection, mq: MessageQueueConnection) {
   val run = IO(println("Hello World!"))
 }

 val module = new ModuleDef {
   make[DBConnection].fromResource(dbResource)
   make[MessageQueueConnection].fromResource(mqResource)
   make[MyApp]
 }

 Injector[IO]()
   .produceGet[MyApp](module)
   .use(_.run())
   .unsafeRunSync()

Will produce the following output:

 Connecting to DB!
 Connecting to Message Queue!
 Hello World!
 Disconnecting Message Queue
 Disconnecting DB

The lifecycle of the entire object graph is itself expressed with Lifecycle, you can control it by controlling the scope of .use or by manually invoking Lifecycle#acquire and Lifecycle#release.

== Inheritance helpers ==

The following helpers allow defining Lifecycle sub-classes using expression-like syntax:

The main reason to employ them is to workaround a limitation in Scala 2's eta-expansion — when converting a method to a function value, Scala always tries to fulfill implicit parameters eagerly instead of making them parameters of the function value, this limitation makes it harder to inject implicits using distage.

However, when using distage's type-based syntax: make[A].fromResource[A.Resource[F]] — this limitation does not apply and implicits inject successfully.

So to workaround the limitation you can convert an expression based resource-constructor such as:

 import distage.Lifecycle, cats.Monad

 class A
 object A {
   def resource[F[_]](implicit F: Monad[F]): Lifecycle[F, A] = Lifecycle.pure(new A)
 }

Into a class-based form:

 import distage.Lifecycle, cats.Monad

 class A
 object A {
   final class Resource[F[_]](implicit F: Monad[F])
     extends Lifecycle.Of(
       Lifecycle.pure(new A)
     )
 }

And inject successfully using make[A].fromResource[A.Resource[F]] syntax of izumi.distage.model.definition.dsl.ModuleDefDSL.

The following helpers ease defining Lifecycle subclasses using traditional inheritance where acquire/release parts are defined as methods:

Attributes

See also
Companion
object
Graph
Supertypes
class Object
trait Matchable
class Any
Known subtypes
trait Basic[F, A]
class ContainerResource[F, Tag]
class Resource[F]
class NetworkResource[F, T]
class Make[F, A]
class Make_[F, A]
class NoClose[F, A]
trait Simple[A]
trait FromCats[F, A]
trait FromPair[F, A]
class MakePair[F, A]
trait FromZIO[R, E, A]
trait FromZIOManaged[R, E, A]
trait FromZIOScoped[R, E, A]
class NoCloseBase[F, A]
class LiftF[F, A]
class SelfNoClose[F, A]
trait MutableNoClose[A]
trait OfInner[F, A]
class Of[F, A]
class FromAutoCloseable[F, A]
class OfCats[F, A]
class OfZIO[R, E, A]
class OfZLayer[R, E, A]
class OfZManaged[R, E, A]
trait Self[F, A]
trait Mutable[A]
trait SelfOf[F, A]
trait MutableOf[A]
Show all

Members list

Type members

Types

Value members

Abstract methods

The action in F used to acquire the resource.

The action in F used to acquire the resource.

Attributes

Note

the acquire action is performed uninterruptibly by Lifecycle.SyntaxUse#use and other interpreters, when F is an effect type that supports interruption/cancellation.

def extract[B >: A](resource: InnerResource): Either[F[B], B]

Either an action in F or a pure function used to extract the A from the InnerResource

Either an action in F or a pure function used to extract the A from the InnerResource

The effect in the Left branch will be performed interruptibly, it is not afforded the same kind of safety as acquire and release actions when F is an effect type that supports interruption/cancellation.

When F is Identity, it doesn't matter whether the output is a Left or Right branch.

When consuming the output of extract you can use _.fold(identity, F.pure) to convert the Either to F[B]

Attributes

See also

Lifecycle.Basic extract doesn't have to be defined when inheriting from Lifecycle.Basic

Note

the extract action is performed interruptibly by Lifecycle.SyntaxUse#use and other interpreters

def release(resource: InnerResource): F[Unit]

The action in F used to release, close or deallocate the resource after it has been acquired and used through Lifecycle.SyntaxUse#use.

The action in F used to release, close or deallocate the resource after it has been acquired and used through Lifecycle.SyntaxUse#use.

Attributes

Note

the release action is performed uninterruptibly by Lifecycle.SyntaxUse#use and other interpreters, when F is an effect type that supports interruption/cancellation.

Concrete methods

final def beforeAcquire[G[x] : QuasiApplicative](f: => G[Unit]): Lifecycle[G, A]
final def beforeRelease[G[x] : QuasiApplicative](f: InnerResource => G[Unit]): Lifecycle[G, A]

Prepend release action to existing

Prepend release action to existing

Attributes

final def catchAll[G[x] : QuasiIO, B >: A](recover: Throwable => Lifecycle[G, B]): Lifecycle[G, B]
final def catchSome[G[x] : QuasiIO, B >: A](recover: PartialFunction[Throwable, Lifecycle[G, B]]): Lifecycle[G, B]
final def evalMap[G[x] : QuasiPrimitives, B](f: A => G[B]): Lifecycle[G, B]
final def evalTap[G[x] : QuasiPrimitives](f: A => G[Unit]): Lifecycle[G, A]
final def flatMap[G[x] : QuasiPrimitives, B](f: A => Lifecycle[G, B]): Lifecycle[G, B]
final def flatten[G[x], B](implicit evidence$1: QuasiPrimitives[G], ev: A <:< Lifecycle[G, B]): Lifecycle[G, B]
final def map[G[x] : QuasiFunctor, B](f: A => B): Lifecycle[G, B]
final def mapK[G[x], H[_]](f: Morphism1[G, H]): Lifecycle[H, A]
final def redeem[G[x] : QuasiIO, B](onFailure: Throwable => Lifecycle[G, B], onSuccess: A => Lifecycle[G, B]): Lifecycle[G, B]
def toCats[G[x] : Applicative]: Resource[G, A]
Implicitly added by SyntaxLifecycleCats

Convert Lifecycle to cats.effect.Resource

Convert Lifecycle to cats.effect.Resource

Attributes

def toEffect[F[_]](implicit F: QuasiIO[F]): Lifecycle[F, A]
Implicitly added by SyntaxLifecycleIdentity
def toZIO: ZIO[Scope & R, E, A]
Implicitly added by SyntaxLifecycleZIO

Convert Lifecycle to scoped zio.ZIO

Convert Lifecycle to scoped zio.ZIO

Attributes

def toZManaged: ZManaged[R, E, A]
Implicitly added by SyntaxLifecycleZManaged

Convert Lifecycle to zio.managed.ZManaged

Convert Lifecycle to zio.managed.ZManaged

Attributes

def unsafeAllocate()(implicit F: QuasiPrimitives[F]): F[(A, () => F[Unit])]
Implicitly added by SyntaxUnsafeGet

Unsafely acquire the resource, return it and the finalizer. The resource will be leaked unless the finalizer is used.

Unsafely acquire the resource, return it and the finalizer. The resource will be leaked unless the finalizer is used.

This function usually only makes sense in code examples or at top-level, please use SyntaxUse#use otherwise!

Attributes

Note

will acquire the resource without an uninterruptible section

def unsafeGet()(implicit F: QuasiPrimitives[F]): F[A]
Implicitly added by SyntaxUnsafeGet

Unsafely acquire the resource and throw away the finalizer, this will leak the resource and cause it to never be cleaned up.

Unsafely acquire the resource and throw away the finalizer, this will leak the resource and cause it to never be cleaned up.

This function usually only makes sense in code examples or at top-level, please use SyntaxUse#use otherwise!

Attributes

Note

will acquire the resource without an uninterruptible section

def use[G[x], B](use: A => G[B])(implicit F: QuasiPrimitives[G]): G[B]
Implicitly added by SyntaxUse

The main entrypoint for using a Lifecycle

The main entrypoint for using a Lifecycle

Attributes

Example
open(file1).use {
 reader1 =>
   open(file2).use {
     reader2 =>
       readFiles(reader1, reader2)
   }
}
def use[B](use: A => B)(implicit F: QuasiPrimitives[Identity]): B
Implicitly added by SyntaxUseIdentity

workaround for inference issues on Scala 3 for Lifecycle.SyntaxUse#use when F = Identity

workaround for inference issues on Scala 3 for Lifecycle.SyntaxUse#use when F = Identity

Attributes

def useEffect(implicit F: QuasiPrimitives[F]): F[A]
Implicitly added by SyntaxUseEffect
final def void[G[x] : QuasiFunctor]: Lifecycle[G, Unit]
final def widen[B >: A]: Lifecycle[F, B]
final def widen[B](implicit ev: A <:< B): Lifecycle[F, B]
def widenError[E1 >: E]: Lifecycle[[_] =>> F[E1, _$46], A]
Implicitly added by SyntaxWidenError
final def widenF[G[x]]: Lifecycle[G, A]
final def widenF[G[_]](implicit ev: F[Unit] <:< G[Unit]): Lifecycle[G, A]
final def wrapAcquire[G[x]](f: (=> G[InnerResource]) => G[InnerResource]): Lifecycle[G, A]

Wrap acquire action of this resource in another effect, e.g. for logging purposes

Wrap acquire action of this resource in another effect, e.g. for logging purposes

Attributes

final def wrapRelease[G[x]](f: (InnerResource => G[Unit], InnerResource) => G[Unit]): Lifecycle[G, A]

Wrap release action of this resource in another effect, e.g. for logging purposes

Wrap release action of this resource in another effect, e.g. for logging purposes

Attributes