Capture errors thrown inside `bgRun`

This captures non-fatal errors in `bgRun` background thread, so if needed we can re-throw it for `run`.
This commit is contained in:
Eugene Yokota 2017-08-27 02:20:39 -04:00
parent b6f2fe7654
commit 9003ed4fac
3 changed files with 44 additions and 4 deletions

View File

@ -5,6 +5,7 @@ import sbt.util.Logger
import Def.{ ScopedKey, Classpath }
import sbt.internal.util.complete._
import java.io.File
import scala.util.Try
abstract class BackgroundJobService extends Closeable {
@ -24,6 +25,12 @@ abstract class BackgroundJobService extends Closeable {
def shutdown(): Unit
def jobs: Vector[JobHandle]
def stop(job: JobHandle): Unit
def waitForTry(job: JobHandle): Try[Unit] = {
// This implementation is provided only for backward compatibility.
Try(waitFor(job))
}
def waitFor(job: JobHandle): Unit
/** Copies classpath to temporary directories. */

View File

@ -1168,14 +1168,14 @@ object Defaults extends BuildCommon {
Def.inputTask {
val handle = bgRunMain.evaluated
val service = bgJobService.value
service.waitFor(handle)
service.waitForTry(handle).get
}
// run calls bgRun in the background and waits for the result.
def foregroundRunTask: Initialize[InputTask[Unit]] =
Def.inputTask {
val handle = bgRun.evaluated
val service = bgJobService.value
service.waitFor(handle)
service.waitForTry(handle).get
}
def runMainTask(classpath: Initialize[Task[Classpath]],
scalaRun: Initialize[Task[ScalaRun]]): Initialize[InputTask[Unit]] = {

View File

@ -5,6 +5,7 @@ import java.util.concurrent.atomic.AtomicLong
import java.io.Closeable
import Def.{ ScopedKey, Setting, Classpath }
import scala.concurrent.ExecutionContext
import scala.util.Try
import Scope.GlobalScope
import java.io.File
import sbt.io.{ IO, Hash }
@ -18,6 +19,13 @@ import sbt.internal.util.{ Attributed, ManagedLogger }
private[sbt] abstract class BackgroundJob {
def humanReadableName: String
def awaitTermination(): Unit
/** This waits till the job ends, and returns inner error via `Try`. */
def awaitTerminationTry(): Try[Unit] = {
// This implementation is provided only for backward compatibility.
Try(awaitTermination())
}
def shutdown(): Unit
// this should be true on construction and stay true until
// the job is complete
@ -132,15 +140,27 @@ private[sbt] abstract class AbstractBackgroundJobService extends BackgroundJobSe
private def withHandle(job: JobHandle)(f: ThreadJobHandle => Unit): Unit = job match {
case handle: ThreadJobHandle @unchecked => f(handle)
case dead: DeadHandle @unchecked => () // nothing to stop or wait for
case _: DeadHandle @unchecked => () // nothing to stop or wait for
case other =>
sys.error(
s"BackgroundJobHandle does not originate with the current BackgroundJobService: $other")
}
private def withHandleTry(job: JobHandle)(f: ThreadJobHandle => Try[Unit]): Try[Unit] =
job match {
case handle: ThreadJobHandle @unchecked => f(handle)
case _: DeadHandle @unchecked => Try(()) // nothing to stop or wait for
case other =>
Try(sys.error(
s"BackgroundJobHandle does not originate with the current BackgroundJobService: $other"))
}
override def stop(job: JobHandle): Unit =
withHandle(job)(_.job.shutdown())
override def waitForTry(job: JobHandle): Try[Unit] =
withHandleTry(job)(_.job.awaitTerminationTry())
override def waitFor(job: JobHandle): Unit =
withHandle(job)(_.job.awaitTermination())
@ -212,6 +232,9 @@ private[sbt] class BackgroundThreadPool extends java.io.Closeable {
@volatile
private var status: Status = Waiting
// This is used to capture exceptions that are caught in this background job.
private var exitTry: Option[Try[Unit]] = None
// double-finally for extra paranoia that we will finishedLatch.countDown
override def run() =
try {
@ -226,7 +249,11 @@ private[sbt] class BackgroundThreadPool extends java.io.Closeable {
throw new RuntimeException("Impossible status of bg thread")
}
}
try { if (go) body() } finally cleanup()
try {
if (go) {
exitTry = Option(Try(body()))
}
} finally cleanup()
} finally finishedLatch.countDown()
private class StopListener(val callback: () => Unit, val executionContext: ExecutionContext)
@ -269,6 +296,12 @@ private[sbt] class BackgroundThreadPool extends java.io.Closeable {
result
}
override def awaitTermination(): Unit = finishedLatch.await()
override def awaitTerminationTry(): Try[Unit] = {
awaitTermination()
exitTry.getOrElse(Try(()))
}
override def humanReadableName: String = taskName
override def isRunning(): Boolean =
status match {