Skip to content

Commit 0f33af5

Browse files
authored
Merge pull request #564 from romanowski/bsp-recover
In case of error from bloop shout down bsp server
2 parents 2e2adce + 8a87361 commit 0f33af5

File tree

3 files changed

+67
-2
lines changed

3 files changed

+67
-2
lines changed

modules/build/src/main/scala/scala/build/bsp/BspImpl.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -352,6 +352,7 @@ final class BspImpl(
352352
.create()
353353
val remoteClient = launcher.getRemoteProxy
354354
actualLocalClient.forwardToOpt = Some(remoteClient)
355+
actualLocalServer.onConnectWithClient(actualLocalClient)
355356

356357
for (targetId <- actualLocalServer.targetIds)
357358
inputs.flattened().foreach {

modules/build/src/main/scala/scala/build/bsp/BspServer.scala

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
package scala.build.bsp
22

3+
import ch.epfl.scala.bsp4j.{BuildClient, LogMessageParams, MessageType}
34
import ch.epfl.scala.{bsp4j => b}
45

5-
import java.util.concurrent.CompletableFuture
6+
import java.io.{PrintWriter, StringWriter}
7+
import java.util.concurrent.{CompletableFuture, TimeUnit}
68
import java.{util => ju}
79

810
import scala.build.Logger
@@ -11,6 +13,7 @@ import scala.build.internal.Constants
1113
import scala.build.options.Scope
1214
import scala.concurrent.{Future, Promise}
1315
import scala.jdk.CollectionConverters._
16+
import scala.util.Random
1417

1518
class BspServer(
1619
bloopServer: b.BuildServer with b.ScalaBuildServer with b.JavaBuildServer with ScalaDebugServer,
@@ -21,11 +24,30 @@ class BspServer(
2124
with ScalaDebugServerForwardStubs
2225
with ScalaBuildServerForwardStubs with JavaBuildServerForwardStubs with HasGeneratedSources {
2326

27+
private var client: Option[BuildClient] = None
28+
29+
override def onConnectWithClient(client: BuildClient): Unit = this.client = Some(client)
30+
2431
private var extraDependencySources: Seq[os.Path] = Nil
2532
def setExtraDependencySources(sourceJars: Seq[os.Path]): Unit = {
2633
extraDependencySources = sourceJars
2734
}
2835

36+
// Can we accept some errors in some circumstances?
37+
override protected def onFatalError(throwable: Throwable, context: String): Unit = {
38+
val sw = new StringWriter()
39+
throwable.printStackTrace(new PrintWriter(sw))
40+
val message =
41+
s"Fatal error has occured within $context. Shutting down the server:\n ${sw.toString}"
42+
System.err.println(message)
43+
client.foreach(_.onBuildLogMessage(new LogMessageParams(MessageType.ERROR, message)))
44+
45+
// wait random bit before shutting down server to reduce risk of multiple scala-cli instances starting bloop at the same time
46+
val timeout = Random.nextInt(400)
47+
TimeUnit.MILLISECONDS.sleep(100 + timeout)
48+
sys.exit(1)
49+
}
50+
2951
private def maybeUpdateProjectTargetUri(res: b.WorkspaceBuildTargetsResult): Unit =
3052
for {
3153
(_, n) <- projectNames.iterator

modules/build/src/main/scala/scala/build/bsp/BuildServerForwardStubs.scala

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,40 +4,82 @@ import ch.epfl.scala.bsp4j.{DependencyModulesParams, DependencyModulesResult}
44
import ch.epfl.scala.{bsp4j => b}
55

66
import java.util.concurrent.CompletableFuture
7+
import java.util.function.BiFunction
78

89
trait BuildServerForwardStubs extends b.BuildServer {
910
protected def forwardTo: b.BuildServer
11+
12+
protected def onFatalError(throwable: Throwable, context: String): Unit
13+
14+
def fatalExceptionHandler[T](methodName: String, params: Any*) = new BiFunction[T, Throwable, T] {
15+
override def apply(maybeValue: T, maybeException: Throwable): T =
16+
maybeException match {
17+
case null =>
18+
maybeValue
19+
case error =>
20+
val methodContext = s"bloop bsp server, method: $methodName"
21+
val context =
22+
if (params.isEmpty) methodContext
23+
else
24+
params.mkString(s"$methodContext, with params: ", ", ", "")
25+
onFatalError(error, context)
26+
throw error
27+
}
28+
}
29+
1030
override def buildShutdown(): CompletableFuture[Object] =
11-
forwardTo.buildShutdown()
31+
forwardTo.buildShutdown().handleAsync(fatalExceptionHandler("buildShutdown"))
32+
1233
override def buildTargetCleanCache(
1334
params: b.CleanCacheParams
1435
): CompletableFuture[b.CleanCacheResult] =
1536
forwardTo.buildTargetCleanCache(params)
37+
.handleAsync(fatalExceptionHandler("buildTargetCleanCache", params))
38+
1639
override def buildTargetCompile(params: b.CompileParams): CompletableFuture[b.CompileResult] =
1740
forwardTo.buildTargetCompile(params)
41+
.handleAsync(fatalExceptionHandler("buildTargetCompile", params))
42+
1843
override def buildTargetDependencySources(
1944
params: b.DependencySourcesParams
2045
): CompletableFuture[b.DependencySourcesResult] =
2146
forwardTo.buildTargetDependencySources(params)
47+
.handleAsync(fatalExceptionHandler("buildTargetDependencySources", params))
48+
2249
override def buildTargetInverseSources(
2350
params: b.InverseSourcesParams
2451
): CompletableFuture[b.InverseSourcesResult] =
2552
forwardTo.buildTargetInverseSources(params)
53+
.handleAsync(fatalExceptionHandler("buildTargetInverseSources", params))
54+
2655
override def buildTargetResources(
2756
params: b.ResourcesParams
2857
): CompletableFuture[b.ResourcesResult] =
2958
forwardTo.buildTargetResources(params)
59+
.handleAsync(fatalExceptionHandler("buildTargetResources", params))
60+
3061
override def buildTargetRun(params: b.RunParams): CompletableFuture[b.RunResult] =
3162
forwardTo.buildTargetRun(params)
63+
.handleAsync(fatalExceptionHandler("buildTargetRun", params))
64+
3265
override def buildTargetSources(params: b.SourcesParams): CompletableFuture[b.SourcesResult] =
3366
forwardTo.buildTargetSources(params)
67+
.handleAsync(fatalExceptionHandler("buildTargetSources", params))
68+
3469
override def buildTargetTest(params: b.TestParams): CompletableFuture[b.TestResult] =
3570
forwardTo.buildTargetTest(params)
71+
.handleAsync(fatalExceptionHandler("buildTargetTest", params))
72+
3673
override def workspaceBuildTargets(): CompletableFuture[b.WorkspaceBuildTargetsResult] =
3774
forwardTo.workspaceBuildTargets()
75+
.handleAsync(fatalExceptionHandler("workspaceBuildTargets"))
76+
3877
override def workspaceReload(): CompletableFuture[Object] =
3978
forwardTo.workspaceReload()
79+
.handleAsync(fatalExceptionHandler("workspaceReload"))
80+
4081
override def buildTargetDependencyModules(params: DependencyModulesParams)
4182
: CompletableFuture[DependencyModulesResult] =
4283
forwardTo.buildTargetDependencyModules(params)
84+
.handleAsync(fatalExceptionHandler("buildTargetDependencyModules", params))
4385
}

0 commit comments

Comments
 (0)