Si ejecuto este programa desde el shell SBT, luego lo cancelo, seguirá imprimiendo "hola". Tengo que salir de SBT para que se detenga. ¿Porqué es eso?

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 feb. 2021 a las 19:16

1 respuesta

La mejor respuesta

Como ya se mencionó en los comentarios, su aplicación se ejecuta en otro hilo y nunca termina ya que el flujo es infinito, por lo que tendrá que terminarlo manualmente cuando la aplicación reciba una señal como SIGTERM o SIGINT (se emite siempre que presionas ctrl+c para terminar la aplicación).

Podrías hacer algo como esto:

  1. crear una instancia de Diferido
  2. Úselo para activar interruptWhen después de que se reciba cualquiera de las señales TERM o INT.

Por ejemplo:

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

}

Esta versión de la aplicación terminará cada vez que presione ctrl + c en sbt shell.

1
Krzysztof Atłasik 7 mar. 2021 a las 08:50