Skip to content

Initialization error when using unsafe.implicits.global within IOApp #1918

@gvolpe

Description

@gvolpe

While updating some examples that demonstrate what not to do, I bumped into this issue. Here's my example.

import scala.concurrent.duration._

import cats.effect._
import cats.effect.std.{ Semaphore, Supervisor }
import cats.effect.unsafe.implicits.global

object LeakyState extends IOApp.Simple {

  // global access
  val sem: Semaphore[IO] =
    Semaphore[IO](1).unsafeRunSync()

  def launchMissiles: IO[Unit] =
    sem.permit
      .use { _ =>
        IO.println("Launching missiles") >>
          IO.sleep(3.seconds) >>
          IO.println("Missiles launched, releasing lock")
      }

  def randomSleep: IO[Unit] =
    IO(scala.util.Random.nextInt(100)).flatMap { ms =>
      IO.sleep((ms + 700).millis)
    }.void

  def p1: IO[Unit] =
    sem.permit.use(_ => IO.println("Running P1")) >> randomSleep

  def p2: IO[Unit] =
    sem.permit.use(_ => IO.println("Running P2")) >> randomSleep

  def run: IO[Unit] =
    Supervisor[IO].use { s =>
      s.supervise(launchMissiles) *>
        s.supervise(p1.foreverM).void *>
        s.supervise(p2.foreverM).void *>
        IO.sleep(5.seconds).void
    }

}

Initializing (unsafely) the Semaphore fails with this error.

[info] running (fork) examples.state.LeakyState
[error] Exception in thread "main" java.lang.IllegalArgumentException: requirement failed
[error] 	at scala.Predef$.require(Predef.scala:325)
[error] 	at cats.effect.unsafe.IORuntimeCompanionPlatform.installGlobal(IORuntimeCompanionPlatform.scala:67)
[error] 	at cats.effect.IOApp.main(IOApp.scala:58)
[error] 	at cats.effect.IOApp.main$(IOApp.scala:35)
[error] 	at examples.state.LeakyState$.main(LeakyState.scala:9)
[error] 	at examples.state.LeakyState.main(LeakyState.scala)

Even when setting Compile / run / fork := true in build.sbt.

The workaround is to make it a lazy val together with forking enabled in sbt. So this does not work in Scastie: https://scastie.scala-lang.org/v7S7tnCsQ9yAL9gMSnxyhw

Since this example showcases exactly what users should not do, I don't expect a fix but raising the issue in case this could be a legit bug when interoping with side-effectful frameworks, e.g. initializing an ActorSystem within IOApp.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions