0

帮助我如何在 ZIO 上组织目录扫描。这是我的版本,但它不会跟踪所有文件创建事件(错过一些事件)。

object Main extends App {

  val program = for {
    stream <- ZIO.succeed(waitEvents)
    _ <- stream.run(ZSink.foreach(k => putStrLn(k.map(e => (e.kind(), e.context())).mkString("\n"))))
  } yield ()

  val managedWatchService = ZManaged.make {
    for {
      watchService <- FileSystem.default.newWatchService
      path = Path("c:/temp")
      _ <- path.register(watchService,
        StandardWatchEventKinds.ENTRY_CREATE,
        StandardWatchEventKinds.ENTRY_DELETE
      )
    } yield watchService
  }(_.close.orDie)

  val lookKey = ZManaged.make {
    managedWatchService.use(watchService => watchService.take)
  }(_.reset)

  val waitEvents = ZStream.fromEffect {
    lookKey.use(key => key.pollEvents)
  }.repeat(Schedule.forever)

  override def run(args: List[String]): ZIO[zio.ZEnv, Nothing, ExitCode] =
    program
      .provideLayer(Console.live ++ Blocking.live ++ Clock.live)
      .exitCode
  
}

感谢您的意见。

4

1 回答 1

2

WatchService每次轮询事件时,您都在强制关闭并重新创建。由于这可能涉及某些系统句柄,因此它可能相当慢,因此您可能会丢失介于两者之间的文件事件。您更有可能想要生成WatchService一次然后重复轮询它。我会建议这样的东西:

object Main extends App {        
  val managedWatchService = ZManaged.make {
    for {
      watchService <- FileSystem.default.newWatchService
      path = Path("c:/temp")
      _ <- path.register(watchService,
        StandardWatchEventKinds.ENTRY_CREATE,
        StandardWatchEventKinds.ENTRY_DELETE
      )
    } yield watchService
  }(_.close.orDie)
      
  // Convert ZManaged[R, E, ZStream[R, E, A]] into ZStream[R, E, A]
  val waitEvents = ZStream.unwrapManaged(
    managedWatchService.mapM(_.take).map { key =>
      // Use simple effect composition instead of a managed for readability.
      ZStream.repeatEffect(key.pollEvents <* key.reset)
       // Optional: Flatten the `List` of values that is returned
       .flattenIterables
    }
  )

  val program = waitEvents
    .map(e => (e.kind(), e.context()).toString)
    .foreach(putStrLn).unit

  override def run(args: List[String]): ZIO[zio.ZEnv, Nothing, ExitCode] =
    program
      .provideLayer(Console.live ++ Blocking.live ++ Clock.live)
      .exitCode
  
}

另外作为旁注,使用时ZManaged,您可能不想这样做

ZManaged.make(otherManaged.use(doSomething))(tearDown)

因为您将导致终结器无序执行。已经可以通过正常的组合ZManaged来处理拆卸的顺序。flatMap

otherManaged.flatMap { other => ZManaged.make(doSomething(other))(tearDown) }
于 2020-12-14T13:19:29.313 回答