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?
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.
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.
Should be fixed after https://github.com/zio/zio/pull/2339 was merged
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With