All Downloads are FREE. Search and download functionalities are using the official Maven repository.

zio.ZIOAppPlatformSpecific.scala Maven / Gradle / Ivy

There is a newer version: 2.1.11
Show newest version
package zio

import zio.internal._
import zio.stacktracer.TracingImplicits.disableAutoTrace

private[zio] trait ZIOAppPlatformSpecific { self: ZIOApp =>

  /**
   * The Scala main function, intended to be called only by the Scala runtime.
   */
  final def main(args0: Array[String]): Unit = {
    implicit val trace: Trace   = Trace.empty
    implicit val unsafe: Unsafe = Unsafe.unsafe

    val newLayer =
      ZLayer.succeed(ZIOAppArgs(Chunk.fromIterable(args0))) >>>
        bootstrap +!+ ZLayer.environment[ZIOAppArgs]

    val workflow =
      (for {
        runtime <- ZIO.runtime[Environment with ZIOAppArgs]
        _       <- installSignalHandlers(runtime)
        result  <- runtime.run(ZIO.scoped[Environment with ZIOAppArgs](run)).tapErrorCause(ZIO.logErrorCause(_))
      } yield result).provideLayer(newLayer.tapErrorCause(ZIO.logErrorCause(_)))

    runtime.unsafe.run {
      ZIO.uninterruptibleMask { restore =>
        for {
          fiberId <- ZIO.fiberId
          p       <- Promise.make[Nothing, Set[FiberId.Runtime]]
          fiber <- restore(workflow).onExit { exit0 =>
                     val exitCode  = if (exit0.isSuccess) ExitCode.success else ExitCode.failure
                     val interrupt = interruptRootFibers(p)
                     // If we're shutting down due to an external signal, the shutdown hook will fulfill the promise
                     // Otherwise it means we're shutting down due to normal completion and we need to fulfill the promise
                     ZIO.unless(shuttingDown.get())(p.succeed(Set(fiberId))) *> interrupt *> exit(exitCode)
                   }.fork
          _ <-
            ZIO.succeed(Platform.addShutdownHook { () =>
              if (!shuttingDown.getAndSet(true)) {

                if (FiberRuntime.catastrophicFailure.get) {
                  println(
                    "**** WARNING ****\n" +
                      "Catastrophic error encountered. " +
                      "Application not safely interrupted. " +
                      "Resources may be leaked. " +
                      "Check the logs for more details and consider overriding `Runtime.reportFatal` to capture context."
                  )
                } else {
                  try {
                    val completePromise = ZIO.fiberIdWith(fid2 => p.succeed(Set(fiberId, fid2)))
                    runtime.unsafe.run(completePromise *> fiber.interrupt)
                  } catch {
                    case _: Throwable =>
                  }
                }

                ()
              }
            })
          result <- fiber.join
        } yield result
      }
    }.getOrThrowFiberFailure()
  }

  private def interruptRootFibers(p: Promise[Nothing, Set[FiberId.Runtime]])(implicit trace: Trace): UIO[Unit] =
    for {
      ignoredIds <- p.await
      roots      <- Fiber.roots
      _          <- Fiber.interruptAll(roots.view.filter(fiber => fiber.isAlive() && !ignoredIds(fiber.id)))
    } yield ()

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy