5

我想在 ZIO Fibers 上使用组合器 orElse。来自文档:

如果第一根光纤成功,则组合光纤将成功并获得结果;否则,组合的纤程将以第二个纤程的退出值完成(无论成功还是失败)。

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)
}

我在控制台中使用 sbt 运行它。并输出:

[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>

我看到秒 Fiber 的结果,结果是 [2] 但是为什么它会输出这些不必要的异常/警告消息?

4

2 回答 2

4

Platform发生这种情况是因为被创建的默认实例zio.App具有向控制台报告不间断的失败光纤的默认值:

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

为避免这种情况,您可以提供自己Platform不这样做的实例:

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)
}

产生:

Result is [2]

正如@Adam Fraser 所指出的,这可能会在附近的版本中得到修复。

编辑:

应该在https://github.com/zio/zio/pull/2339被合并后修复

于 2019-11-27T14:40:26.143 回答
4

默认情况下,当未连接回的光纤发生故障时,会生成光纤故障警告,以免错误丢失。但是正如您在某些情况下正确指出的那样,这不是必需的,因为错误是由程序逻辑在内部处理的,在这种情况下是由orElse组合器处理的。我们一直在处理其他几个生成虚假警告的案例,我刚刚在这里开了一张票。我希望我们会在下一个版本中解决这个问题。

于 2019-11-27T14:30:22.850 回答