Monix BIO

Monix BIO

  • API Docs
  • Documentation
  • GitHub

›Documentation

Documentation

  • Introduction
  • Getting Started
  • Creating IO
  • Executing IO
  • Error Handling
  • Resource Safety
  • Cats-Effect Integration
  • Asynchronous Stack Traces
  • Other Effects

Executing IO

As mentioned in other sections, IO is lazily evaluated - it needs to be executed to start doing anything.

BIOApp

The ideal way to use IO is to run it only once at the edge of your program, in Main.

You can go a step further and use BIOApp to run the effect for you and prepare a basic environment. BIOApp piggybacks on IOApp from Cats-Effect which brings convenient features like safely releasing resources in case of Ctrl-C or kill command.

import cats.effect._
import monix.bio._

object Main extends BIOApp {
  def run(args: List[String]): UIO[ExitCode] =
    args.headOption match {
      case Some(name) =>
        UIO(println(s"Hello, $name.")).map(_ => ExitCode.Success)
      case None =>
        UIO(System.err.println("Usage: MyApp name")).map(_ => ExitCode(2))
    }
}

Manual Execution

If you'd prefer to run manually, there are plenty of options. This section will cover just a few ones - all variants are prefixed with "run" and should be easy to find in API. As an optimization, IO will run on the current thread up to the first asynchronous boundary. You can use executeAsync to make sure entire task will run asynchronously.

Note that all methods to run IO require Scheduler. Examples will use Scheduler.global, which is a good default for most applications.

Running to Future

IO.runToFuture starts the execution and returns a CancelableFuture, which will complete when the task finishes. CancelableFuture extends standard scala.concurrent.Future and adds an ability to cancel it. Calling cancel will plug into IO cancelation.

import monix.bio.Task
import monix.execution.CancelableFuture
import scala.concurrent.duration._

implicit val s = monix.execution.Scheduler.global

val task = Task(1 + 1).delayExecution(1.second)

val result: CancelableFuture[Int] =
  task.runToFuture

// If we change our mind
result.cancel()

All potential errors will be exposed as a failed Future. One gotcha is that runToFuture requires error type to be E <:< Throwable. Thankfully, it also applies to Nothing, so if we work with typed errors, we can handle error just before running IO. Probably the most convenient way is to use attempt:

import monix.bio.IO
import monix.execution.CancelableFuture

implicit val s = monix.execution.Scheduler.global

val task: IO[Int, Int] = IO.raiseError(20)

val result: CancelableFuture[Either[Int, Int]] =
  task.attempt.runToFuture

Typed errors will be exposed as Left, and terminal errors will result in a failed Future.

Running with a callback

If returning a Future is too heavy for your needs, you can use def runAsync, which accepts a callback and returns a cancelation token.

import monix.bio.Cause
import monix.bio.Task
import scala.concurrent.duration._

implicit val s = monix.execution.Scheduler.global

val task = Task(1 + 1).delayExecution(1.second)

val cancelable = task.runAsync {
  case Right(value) =>
    println(value)
  case Left(Cause.Error(ex)) =>
    System.err.println(s"ERROR: ${ex.getMessage}")
  case Left(Cause.Termination(ex)) =>
    System.err.println(s"TERMINATION: ${ex.getMessage}")
}

// If we change our mind...
cancelable.cancel()

If your needs are even more modest, use runAsyncAndForget, which will run IO in "fire-and-forget" fashion.

Blocking for a result

Monix is against blocking threads, but when you have to do it, you can use runSyncUnsafe, or runToFuture in combination with Await.result from the standard library.

← Creating IOError Handling →
  • BIOApp
  • Manual Execution
    • Running to Future
    • Running with a callback
    • Blocking for a result

Copyright © 2019-2021 The Monix Project Developers.