Skip to content

Commit

Permalink
Restart whole bsp on timeout
Browse files Browse the repository at this point in the history
  • Loading branch information
rochala committed Dec 20, 2023
1 parent 7d9a990 commit 7bf703c
Show file tree
Hide file tree
Showing 5 changed files with 73 additions and 186 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@ object BspClient {
Option(diag.getRange.getStart.getLine + Instrument.getMessageLineOffset(isWorksheet, isScalaCli = true)),
diag.getMessage()
)

val scalaCliExec = Seq("cs", "launch", "org.virtuslab.scala-cli:cliBootstrapped:latest.release", "-M", "scala.cli.ScalaCli", "--")
}

trait ScalaCliServer extends BuildServer with ScalaBuildServer with JvmBuildServer
Expand All @@ -91,13 +93,14 @@ class BspClient(coloredStackTrace: Boolean, workingDir: Path, compilationTimeout
private val localClient = new InnerClient()
private val es = Executors.newFixedThreadPool(1)

Process(Seq("scala-cli", "clean", workingDir.toAbsolutePath.toString)).!
Process(Seq("scala-cli", "setup-ide", workingDir.toAbsolutePath.toString)).!
val scalaCliExec = Seq("cs", "launch", "org.virtuslab.scala-cli:cliBootstrapped:latest.release", "-M", "scala.cli.ScalaCli", "--")
Process(scalaCliExec ++ Seq("clean", workingDir.toAbsolutePath.toString)).!
Process(scalaCliExec ++ Seq("setup-ide", workingDir.toAbsolutePath.toString)).!

private val processBuilder: java.lang.ProcessBuilder = new java.lang.ProcessBuilder()
val logFile = Files.createFile(workingDir.toAbsolutePath.resolve("bsp.error.log"))
val logFile = workingDir.toAbsolutePath.resolve("bsp.error.log")
processBuilder
.command("scala-cli", "--cli-version", "nightly", "bsp", "-v", "-v", "-v", workingDir.toAbsolutePath.toString)
.command((scalaCliExec ++ Seq("bsp", workingDir.toAbsolutePath.toString)):_*)
.redirectError(logFile.toFile)

val scalaCliServer = processBuilder.start()
Expand Down Expand Up @@ -258,7 +261,7 @@ class BspClient(coloredStackTrace: Boolean, workingDir: Path, compilationTimeout
// Kills the BSP connection and makes this object
// un-usable.
def end() = {
Process("scala-cli --power bloop exit").!
Process(BspClient.scalaCliExec ++ Seq("--power", "bloop", "exit")).!
try {
log.info("Sending buildShutdown.")
bspServer.buildShutdown().get(30, TimeUnit.SECONDS)
Expand Down Expand Up @@ -297,10 +300,7 @@ class BspClient(coloredStackTrace: Boolean, workingDir: Path, compilationTimeout

log.info("Stopping listening thread.")
listening.cancel(true)
Files.readString(logFile).linesIterator.foreach(log.error(_))
}

Thread.sleep(5000)
}

class InnerClient extends BuildClient {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,12 +102,13 @@ class ScalaCliActor(
isDone = true
))
case Left(BspTaskTimeout(msg)) =>
Process("scala-cli --power bloop exit").!
Process("scala-cli --power bloop start").!
log.warning("Timeout detected, restarting BSP")
runner.restart()
sendProgress(progressActor, author, buildErrorProgress(snippetId, msg, progressId.getAndIncrement(), isTimeout = true))
case Left(RuntimeTimeout(msg)) =>
sendProgress(progressActor, author, buildErrorProgress(snippetId, msg, progressId.getAndIncrement(), isTimeout = true))
case Left(error) =>
log.error(s"Error reported: ${error.msg}")
sendProgress(progressActor, author, buildErrorProgress(snippetId, error.msg, progressId.getAndIncrement()))
}.recover {
case error =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ case class RunOutput(
class ScalaCliRunner(coloredStackTrace: Boolean, workingDir: Path, compilationTimeout: FiniteDuration, reloadTimeout: FiniteDuration) {

private val log = Logger("ScalaCliRunner")
private val bspClient = new BspClient(coloredStackTrace, workingDir, compilationTimeout, reloadTimeout)
private var bspClient = new BspClient(coloredStackTrace, workingDir, compilationTimeout, reloadTimeout)
private val scalaMain = workingDir.resolve("Main.scala")
Files.createDirectories(scalaMain.getParent())

Expand Down Expand Up @@ -136,6 +136,11 @@ class ScalaCliRunner(coloredStackTrace: Boolean, workingDir: Path, compilationTi
}
}

def restart(): Unit = {
bspClient.end()
bspClient = new BspClient(coloredStackTrace, workingDir, compilationTimeout, reloadTimeout)
}

def end(): Unit =
bspClient.end()
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import org.scalatest.funsuite.AnyFunSuite
import org.scalatest.BeforeAndAfterAll
import org.scastie.util.ScastieFileUtil
import java.nio.file.Paths
import java.nio.file.Files
import org.scastie.api.SnippetId
import org.scastie.api._
import org.scastie.runtime.api._
Expand All @@ -25,6 +26,9 @@ import org.scastie.util.StopRunner
import org.scastie.util.RunnerTerminated

class ScalaCliRunnerTest extends TestKit(ActorSystem("ScalaCliRunnerTest")) with ImplicitSender with AnyFunSuiteLike with BeforeAndAfterAll {
val workingDir = Files.createTempDirectory("scastie")
println(workingDir)

setAutoPilot(new AutoPilot {
def run(sender: ActorRef, msg: Any): AutoPilot = {
sender ! s"reply to $msg"
Expand Down Expand Up @@ -322,6 +326,56 @@ class ScalaCliRunnerTest extends TestKit(ActorSystem("ScalaCliRunnerTest")) with
})
}

private val macroCode =
"""import scala.quoted._
|
|object SleepMacro:
| inline def sleep(inline time: Int) =
| ${ wait('time) }
|
| def wait(x: Expr[Int])(using Quotes): Expr[Any] =
| Thread.sleep(x.valueOrAbort)
| x
|""".stripMargin

test("No bsp timeout") {
Files.writeString(workingDir.resolve("SleepMacro.scala"), macroCode)
runCode(longCompilation(1000), isWorksheet = false)(assertUserOutput("test"))
Files.delete(workingDir.resolve("SleepMacro.scala"))
}

test("BSP Timeout") {
Files.writeString(workingDir.resolve("SleepMacro.scala"), macroCode)
runCode(longCompilation(compilationTimeout.toMillis + 5000), isWorksheet = false, allowFailure = true)(assertCompilationInfo { info =>
assert(info.message == "Build Server Timeout Exception" )
})
Files.delete(workingDir.resolve("SleepMacro.scala"))
}

def longCompilation(time: Long): String =
s"""//> using scala 3
|//> using file SleepMacro.scala
|
|@main def hello =
| SleepMacro.sleep($time)
| println("test")
|""".stripMargin

test("BSP Timeout Multiple snippets") {
Files.writeString(workingDir.resolve("SleepMacro.scala"), macroCode)
runCode(longCompilation(compilationTimeout.toMillis + 5000), isWorksheet = false, allowFailure = true)(assertCompilationInfo { info =>
assert(info.message == "Build Server Timeout Exception" )
})
runCode(longCompilation(100), isWorksheet = false, allowFailure = false)(assertUserOutput("test"))

runCode(longCompilation(compilationTimeout.toMillis + 5000), isWorksheet = false, allowFailure = true)(assertCompilationInfo { info =>
assert(info.message == "Build Server Timeout Exception" )
})

runCode(longCompilation(100), isWorksheet = false, allowFailure = false)(assertUserOutput("test"))
Files.delete(workingDir.resolve("SleepMacro.scala"))
}

def assertCompilationInfo(infoAssert: Problem => Any)(progress: SnippetProgress): Boolean = {

val gotCompilationError = progress.compilationInfos.nonEmpty
Expand Down Expand Up @@ -352,8 +406,9 @@ class ScalaCliRunnerTest extends TestKit(ActorSystem("ScalaCliRunnerTest")) with
}

private val timeout = 45.seconds
private val compilationTimeout = 25.seconds

val scalaCliActor = system.actorOf(Props(new ScalaCliActor(runTimeout = timeout, isProduction = false, reconnectInfo = None, coloredStackTrace = false, compilationTimeout = 25.seconds)))
val scalaCliActor = system.actorOf(Props(new ScalaCliActor(runTimeout = timeout, isProduction = false, reconnectInfo = None, coloredStackTrace = false, compilationTimeout = compilationTimeout, workingDir = workingDir)))

private var currentId = 0
private def snippetId = {
Expand Down

0 comments on commit 7bf703c

Please sign in to comment.