Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ZIO Fiber orElse generate exception messages

Tags:

scala

zio

I want to use the combinator orElse on ZIO Fibers. From docs:

If the first fiber succeeds, the composed fiber will succeed with its result; otherwise, the composed fiber will complete with the exit value of the second fiber (whether success or failure).

import zio._
import zio.console._

object MyApp extends App {

  def f1 :Task[Int] = IO.fail(new Exception("f1 fail"))
  def f2 :Task[Int] = IO.succeed(2)

  val myAppLogic =
    for {
      f1f <- f1.fork
      f2f <- f2.fork
      ff  =  f1f.orElse(f2f)
      r   <- ff.join
      _   <- putStrLn(s"Result is [$r]")
    } yield ()

  def run(args: List[String]) =
    myAppLogic.fold(_ => 1, _ => 0)
}

I run it with sbt in console. And output:

[info] Running MyApp
Fiber failed.
A checked error was not handled.
java.lang.Exception: f1 fail
        at MyApp$.f1(MyApp.scala:6)
        at MyApp$.<init>(MyApp.scala:11)
        at MyApp$.<clinit>(MyApp.scala)
        at MyApp.main(MyApp.scala)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
Result is [2]
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at sbt.Run.invokeMain(Run.scala:93)
        at sbt.Run.run0(Run.scala:87)
        at sbt.Run.execute$1(Run.scala:65)
        at sbt.Run.$anonfun$run$4(Run.scala:77)
        at scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.java:12)
        at sbt.util.InterfaceUtil$$anon$1.get(InterfaceUtil.scala:10)
        at sbt.TrapExit$App.run(TrapExit.scala:252)
        at java.lang.Thread.run(Thread.java:748)

Fiber:Id(1574829590403,2) was supposed to continue to: <empty trace>

Fiber:Id(1574829590403,2) ZIO Execution trace: <empty trace>

Fiber:Id(1574829590403,2) was spawned by:

Fiber:Id(1574829590397,1) was supposed to continue to:
  a future continuation at MyApp$.myAppLogic(MyApp.scala:12)
  a future continuation at MyApp$.run(MyApp.scala:19)

Fiber:Id(1574829590397,1) ZIO Execution trace: <empty trace>

Fiber:Id(1574829590397,1) was spawned by:

Fiber:Id(1574829590379,0) was supposed to continue to:
  a future continuation at zio.App.main(App.scala:57)
  a future continuation at zio.App.main(App.scala:56)

[Fiber:Id(1574829590379,0) ZIO Execution trace: <empty trace>

I see the result of seconds Fiber, is Result is [2] But why it output these unnecessary exception/warning messages?

like image 564
Aleksey N Yakushev Avatar asked Nov 27 '19 04:11

Aleksey N Yakushev


2 Answers

By default a fiber failure warning is generated when a fiber that is not joined back fails so that errors do not get lost. But as you correctly note in some cases this is not necessary as the error is handled internally by the program logic, in this case by the orElse combinator. We have been working through a couple of other cases of spurious warnings being generated and I just opened a ticket for this one here. I expect we will have this resolved in the next release.

like image 90
Adam Fraser Avatar answered Oct 08 '22 07:10

Adam Fraser


This happens because the default instance of Platform being created by zio.App has a default which reports uninterrupted, failed fibers to the console:

def reportFailure(cause: Cause[_]): Unit =
    if (!cause.interrupted)
      System.err.println(cause.prettyPrint)

To avoid this, you can provide your own Platform instance which doesn't do so:

import zio._
import zio.console._
import zio.internal.{Platform, PlatformLive}

object MyApp extends App {
  override val Platform: Platform = PlatformLive.Default.withReportFailure(_ => ())

  def f1: Task[Int] = IO.fail(new Exception("f1 fail"))
  def f2: Task[Int] = IO.succeed(2)

  val myAppLogic =
    for {
      f1f <- f1.fork
      f2f <- f2.fork
      ff = f1f.orElse(f2f)
      r <- ff.join
      _ <- putStrLn(s"Result is [$r]")
    } yield ()

  def run(args: List[String]) =
    myAppLogic.fold(_ => 1, _ => 0)
}

Which yields:

Result is [2]

As @Adam Fraser noted, this will probably get fixed in a nearby release.

Edit:

Should be fixed after https://github.com/zio/zio/pull/2339 was merged

like image 39
Yuval Itzchakov Avatar answered Oct 08 '22 07:10

Yuval Itzchakov