A Persistence Framework for Scala and NoSQL

View project on GitHub

choosing your effect

Longevity will wrap the results of all your persistence operations in an “effect”. The effect describes how you would like longevity to handle the blocking nature of database operations. You can choose to use Scala futures, a more functional, IO monad kind of approach, where all side-effects are pushed to the edges of your program, or an entirely synchronous and blocking approach.

We already saw how to use futures in the previous section:

import longevity.context.LongevityContext
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Future

val context = LongevityContext[Future, DomainModel]()

You need to provide an execution context when creating a LongevityContext with a Future effect. The easiest way to do this is to include import scala.concurrent.ExecutionContext.Implicits.global at the top of your file.

For a more functional approach, you can use the cats-effect IO monad:

import cats.effect.IO
import longevity.context.LongevityContext
import longevity.effect.cats.ioEffect
import scala.concurrent.ExecutionContext.Implicits.global

val context = LongevityContext[IO, DomainModel]()

Using IO as an effect also requires an implicit execution context. This execution context is used for synchronous operations. Blocking operations use a separate execution context, where blocking threads are spun up as needed to handle the asynchony. In the code example above, we choose a suitable default execution context for blocking operations. If you wish to explore using your own blocking execution context, take a look at the API for longevity.effect.cats.ioEffect. For an explanation of the reason for using two execution contexts here, please see the “Thread Shifting” section in this IO monad for cats blog post.

If you want a synchronous persistence API, use longevity.effect.Blocking:

import longevity.context.LongevityContext
import longevity.effect.Blocking

val context = LongevityContext[Blocking, DomainModel]()

The type Blocking[A] is equivalent to A, similar to an Id monad like cats.Id. Because of this, the results of persistence operations are unwrapped.

Many more effects are possible, and we intend to provide support for some of the more common Task-like classes in the near future. But you can always provide your own. Simply create your own Effect class by implementing this API, and make your effect implicitly available when constructing your LongevityContext.

Some of the examples in this user manual may assume a Future effect, but you can always intuit how things would look with other effects. For instance, if you see a code example like this:

val createResult: Future[PState[User]] = repo.create(user)

You can assume that it would look like this with the IO effect:

val createResult: IO[PState[User]] = repo.create(user)

Or like this with the Blocking effect:

val createResult: PState[User] = repo.create(user)

The longevity demo project has multiple examples using different effects.

prev: the longevity context
up: the longevity context
next: configuring your longevity context