Si j'exécute ce programme à partir du shell SBT, puis annulez-le, il continuera à imprimer "bonjour". Je dois quitter SBT pour que ça s'arrête. Pourquoi donc?

import cats.effect.{ExitCode, IO, IOApp}
import fs2.Stream
import scala.concurrent.duration._

object FS2 extends IOApp {

  override def run(args: List[String]) = 
      Stream.awakeEvery[IO](5.seconds).map { _ =>
        println("hello")
      }.compile.drain.as(ExitCode.Error)
}
1
Cpt. Senkfuss 25 févr. 2021 à 19:16

1 réponse

Meilleure réponse

Comme cela a déjà été mentionné dans les commentaires, votre application s'exécute dans un autre thread et ne se termine jamais car le flux est infini, vous devrez donc le terminer manuellement lorsqu'un signal comme SIGTERM ou SIGINT est reçu par l'application (il est émis à chaque fois vous appuyez sur ctrl+c pour mettre fin à l'application).

Vous pourriez faire quelque chose comme ça:

  1. créer une instance de Deferred
  2. Utilisez-le pour déclencher interruptWhen après la réception de l'un des signaux TERM ou INT.

Par exemple:

object FS2 extends IOApp {

  override def run(args: List[String]): IO[ExitCode] = for {
    cancel <- Deferred[IO, Either[Throwable, Unit]] //deferred used as flat telling if terminations signal
                                                    //was received
    _ <- (IO.async[Unit]{ cb =>
      Signal.handle(
        new Signal("INT"), //INT and TERM signals are nearly identical, we have to handle both
        (sig: Signal) => cb(Right(()))
      )
      Signal.handle(
        new Signal("TERM"),
        (sig: Signal) => cb(Right(()))
      )
    } *> cancel.complete(Right(()))).start //after INT or TERM signal is intercepted it will complete
                                           //deferred and terminate fiber
                                           //we have to run method start to run waiting for signal in another fiber
                                           //in other case program will block here
    app <- Stream.awakeEvery[IO](1.seconds).map { _ => //your stream
      println("hello")
    }.interruptWhen(cancel).compile.drain.as(ExitCode.Error)  //interruptWhen ends stream when deferred completes
  } yield app

}

Cette version de l'application se terminera chaque fois que vous appuierez sur ctrl + c dans le shell sbt.

1
Krzysztof Atłasik 7 mars 2021 à 08:50