Packages

trait Lifecycle[+F[_], +A] extends AnyRef

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 <- open(file1)
    reader2 <- open(file2)
  } yield (reader1, reader2)
}

Nested resources are released in reverse order of acquisition. Outer resources are released even if an inner use or release fails.

Lifecycle can be used without an effect-type with Lifecycle.Simple it can also mimic Java's initialization-after-construction with Lifecycle.Mutable

Use Lifecycle's to specify lifecycles of objects injected into the object graph.

import distage.{Lifecycle, ModuleDef, Injector}
import cats.effect.IO

class DBConnection
class MessageQueueConnection

val dbResource = Lifecycle.make(IO { println("Connecting to DB!"); new DBConnection })(_ => 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 sub-classes using traditional inheritance where acquire/release parts are defined as methods:

See also

ModuleDef.fromResource

cats.effect.Resource

zio.managed.ZManaged

scoped zio.ZIO

zio.ZLayer

Linear Supertypes
AnyRef, Any
Ordering
  1. Alphabetic
  2. By Inheritance
Inherited
  1. Lifecycle
  2. AnyRef
  3. Any
  1. Hide All
  2. Show All
Visibility
  1. Public
  2. Protected

Type Members

  1. abstract type InnerResource

Abstract Value Members

  1. abstract def acquire: F[InnerResource]

    The action in F used to acquire the resource.

    The action in F used to acquire the resource.

    Note

    the acquire action is performed *uninterruptibly*, when F is an effect type that supports interruption/cancellation.

  2. abstract 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]

    See also

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

  3. abstract 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 izumi.distage.model.definition.Lifecycle.SyntaxUse#use.

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

    Note

    the release action is performed *uninterruptibly*, when F is an effect type that supports interruption/cancellation.

Concrete Value Members

  1. final def !=(arg0: Any): Boolean
    Definition Classes
    AnyRef → Any
  2. final def ##: Int
    Definition Classes
    AnyRef → Any
  3. final def ==(arg0: Any): Boolean
    Definition Classes
    AnyRef → Any
  4. final def asInstanceOf[T0]: T0
    Definition Classes
    Any
  5. final def beforeAcquire[G[x] >: F[x]](f: => G[Unit])(implicit arg0: QuasiApplicative[G]): Lifecycle[G, A]
  6. final def beforeRelease[G[x] >: F[x]](f: (InnerResource) => G[Unit])(implicit arg0: QuasiApplicative[G]): Lifecycle[G, A]

    Prepend release action to existing

  7. final def catchAll[G[x] >: F[x], B >: A](recover: (Throwable) => Lifecycle[G, B])(implicit arg0: QuasiIO[G]): Lifecycle[G, B]
  8. final def catchSome[G[x] >: F[x], B >: A](recover: PartialFunction[Throwable, Lifecycle[G, B]])(implicit arg0: QuasiIO[G]): Lifecycle[G, B]
  9. def clone(): AnyRef
    Attributes
    protected[lang]
    Definition Classes
    AnyRef
    Annotations
    @throws(classOf[java.lang.CloneNotSupportedException]) @native()
  10. final def eq(arg0: AnyRef): Boolean
    Definition Classes
    AnyRef
  11. def equals(arg0: AnyRef): Boolean
    Definition Classes
    AnyRef → Any
  12. final def evalMap[G[x] >: F[x], B](f: (A) => G[B])(implicit arg0: QuasiPrimitives[G]): Lifecycle[G, B]
  13. final def evalTap[G[x] >: F[x]](f: (A) => G[Unit])(implicit arg0: QuasiPrimitives[G]): Lifecycle[G, A]
  14. def finalize(): Unit
    Attributes
    protected[lang]
    Definition Classes
    AnyRef
    Annotations
    @throws(classOf[java.lang.Throwable])
  15. final def flatMap[G[x] >: F[x], B](f: (A) => Lifecycle[G, B])(implicit arg0: QuasiPrimitives[G]): Lifecycle[G, B]
  16. final def flatten[G[x] >: F[x], B](implicit arg0: QuasiPrimitives[G], ev: <:<[A, Lifecycle[G, B]]): Lifecycle[G, B]
  17. final def getClass(): Class[_ <: AnyRef]
    Definition Classes
    AnyRef → Any
    Annotations
    @native()
  18. def hashCode(): Int
    Definition Classes
    AnyRef → Any
    Annotations
    @native()
  19. final def isInstanceOf[T0]: Boolean
    Definition Classes
    Any
  20. final def map[G[x] >: F[x], B](f: (A) => B)(implicit arg0: QuasiFunctor[G]): Lifecycle[G, B]
  21. final def ne(arg0: AnyRef): Boolean
    Definition Classes
    AnyRef
  22. final def notify(): Unit
    Definition Classes
    AnyRef
    Annotations
    @native()
  23. final def notifyAll(): Unit
    Definition Classes
    AnyRef
    Annotations
    @native()
  24. final def redeem[G[x] >: F[x], B](onFailure: (Throwable) => Lifecycle[G, B], onSuccess: (A) => Lifecycle[G, B])(implicit arg0: QuasiIO[G]): Lifecycle[G, B]
  25. final def synchronized[T0](arg0: => T0): T0
    Definition Classes
    AnyRef
  26. def toString(): String
    Definition Classes
    AnyRef → Any
  27. final def void[G[x] >: F[x]](implicit arg0: QuasiFunctor[G]): Lifecycle[G, Unit]
  28. final def wait(): Unit
    Definition Classes
    AnyRef
    Annotations
    @throws(classOf[java.lang.InterruptedException])
  29. final def wait(arg0: Long, arg1: Int): Unit
    Definition Classes
    AnyRef
    Annotations
    @throws(classOf[java.lang.InterruptedException])
  30. final def wait(arg0: Long): Unit
    Definition Classes
    AnyRef
    Annotations
    @throws(classOf[java.lang.InterruptedException]) @native()
  31. final def widen[B >: A]: Lifecycle[F, B]
    Annotations
    @inline()
  32. final def widenF[G[x] >: F[x]]: Lifecycle[G, A]
    Annotations
    @inline()
  33. final def wrapAcquire[G[x] >: F[x]](f: (=> G[InnerResource]) => G[InnerResource]): Lifecycle[G, A]

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

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

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

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

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

Inherited from AnyRef

Inherited from Any

Ungrouped