Skip to content

Commit

Permalink
Exit BspServerApp cleanly (#13)
Browse files Browse the repository at this point in the history
* Resolved issue where bsp-server wasn't shutting down cleanly.
  • Loading branch information
aishfenton authored Jan 7, 2023
1 parent bf7bc3d commit de19c5b
Show file tree
Hide file tree
Showing 8 changed files with 46 additions and 34 deletions.
4 changes: 2 additions & 2 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ lazy val root = project
.in(file("."))
.settings(
name := "bazel-bsp",
organization := "org.afenton",
version := "0.1.0-SNAPSHOT",
organization := "afenton",
version := "0.0.15",
scalaVersion := scala3Version,
libraryDependencies += "org.typelevel" %% "cats-effect" % "3.4.4",
libraryDependencies += "co.fs2" %% "fs2-core" % "3.3.0",
Expand Down
3 changes: 2 additions & 1 deletion examples/simple-no-errors/.bsp/bazel-bsp.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"scala"
],
"argv": [
"bazel-bsp"
"../../target/universal/stage/bin/bazel-bsp",
"--verbose"
]
}
3 changes: 2 additions & 1 deletion examples/simple-with-errors/.bsp/bazel-bsp.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"scala"
],
"argv": [
"bazel-bsp"
"../../target/universal/stage/bin/bazel-bsp",
"--verbose"
]
}
35 changes: 19 additions & 16 deletions src/main/scala/afenton/bazel/bsp/BazelBspApp.scala
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import fs2.text
import io.bazel.rules_scala.diagnostics.diagnostics.FileDiagnostics
import io.circe.Json
import io.circe.syntax.*
import cats.effect.std.Console

import java.net.ServerSocket
import java.nio.file.Path
Expand All @@ -32,6 +33,7 @@ import cats.data.Nested
import java.nio.file.StandardOpenOption
import scala.concurrent.duration.FiniteDuration
import java.util.concurrent.TimeUnit
import cats.effect.kernel.Deferred

object BazelBspApp
extends CommandIOApp(
Expand All @@ -50,14 +52,14 @@ object BazelBspApp
fs2.text.utf8.encode.andThen(fs2.io.stdout),
fs2.text.utf8.encode.andThen(fs2.io.stderr)
)
.handleErrorWith { e =>
IO.blocking {
System.err.println(
s"ERROR: 💣 💣 💣 \n${e.toString} \n${e.getStackTrace.mkString("\n")}"
)
ExitCode.Error
.handleErrorWith { e =>
IO.blocking {
System.err.println(
s"ERROR: 💣 💣 💣 \n${e.toString} \n${e.getStackTrace.mkString("\n")}"
)
ExitCode.Error
}
}
}
}

val verifySetupOpt =
Expand Down Expand Up @@ -87,11 +89,11 @@ object BazelBspApp
def printVerifyResult(
result: List[(String, Either[String, Unit])]
): IO[Unit] =
result
.traverse_ {
case (n, Right(_)) => IO.println(s"$n")
case (n, Left(err)) => IO.println(s"$n\n $err\n")
}
result
.traverse_ {
case (n, Right(_)) => IO.println(s"$n")
case (n, Left(err)) => IO.println(s"$n\n $err\n")
}

def main: Opts[IO[ExitCode]] =
verboseOpt
Expand Down Expand Up @@ -140,14 +142,13 @@ object BazelBspApp
logger: Logger
): Stream[IO, Unit] =
inStream
// .evalTap(s => logger.trace(s))
.through(jRpcParser(logger))
.evalTap(request => logger.trace(s"request: ${request}"))
.through(messageDispatcher(BspServer.jsonRpcRouter(bspServer)))
.evalTap(response => logger.trace(s"response: ${response}"))
.evalMap {
case resp: Response => outQ.offer(resp)
case u: Unit => IO.unit
case u: Unit => IO.unit
}

private def processOutStream(
Expand All @@ -158,7 +159,6 @@ object BazelBspApp
Stream
.fromQueueUnterminated(outQ, 100)
.map(msg => JRpcConsoleCodec.encode(msg, false))
// .evalTap(msg => logger.trace(msg))
.through(outPipe)

def server(verbose: Boolean)(
Expand All @@ -177,5 +177,8 @@ object BazelBspApp
processOutStream(outPipe, outQ, logger),
logStream
).parJoin(3)
// NB: Allow time for response to get through
.interruptWhen(server.exitSignal)
.onFinalize(Console[IO].errorln("👋 BSP Server Shutting Down"))
_ <- all.compile.drain
yield ExitCode.Success
yield ExitCode.Success
15 changes: 9 additions & 6 deletions src/main/scala/afenton/bazel/bsp/BazelBspServer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,15 @@ import io.circe.syntax._
import java.net.URI
import java.nio.file.Path
import java.nio.file.Paths
import cats.effect.kernel.Deferred

import IOLifts.{asIO, mapToIO}

class BazelBspServer(
client: BspClient,
logger: Logger,
stateRef: Ref[IO, BazelBspServer.ServerState]
stateRef: Ref[IO, BazelBspServer.ServerState],
val exitSignal: Deferred[IO, Either[Throwable, Unit]]
) extends BspServer(client):

def buildInitialize(
Expand Down Expand Up @@ -252,7 +254,7 @@ class BazelBspServer(
def buildExit(params: Unit): IO[Unit] =
for
_ <- logger.info("build/exit")
_ <- IO.canceled
_ <- exitSignal.complete(Right(()))
yield ()

private def doBuildTargetSources(
Expand Down Expand Up @@ -330,10 +332,11 @@ object BazelBspServer:
ServerState(BazelBspServer.TargetSourceMap.empty, Nil, None, None, Nil)

def create(client: BspClient, logger: Logger): IO[BazelBspServer] =
Ref.of[IO, BazelBspServer.ServerState](defaultState)
.map { stateRef =>
BazelBspServer(client, logger, stateRef)
}
for
exitSwitch <- Deferred[IO, Either[Throwable, Unit]]
stateRef <- Ref.of[IO, BazelBspServer.ServerState](defaultState)
yield
BazelBspServer(client, logger, stateRef, exitSwitch)

protected case class TargetSourceMap(
val _targetSources: Map[BuildTargetIdentifier, List[
Expand Down
2 changes: 1 addition & 1 deletion src/main/scala/afenton/bazel/bsp/BuildMetaData.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package afenton.bazel.bsp

object BuildMetaData {
val Version = "0.0.13"
val Version = "0.0.15"
val BspVersion = "2.0.0-M2"
}
3 changes: 2 additions & 1 deletion src/test/scala/afenton/bazel/bsp/End2EndTest.scala
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ import scala.concurrent.duration._

class End2EndTest extends munit.CatsEffectSuite with BspHelpers:

override val munitTimeout = 6.minute
// Long, because Github actions can run slooooow at times
override val munitTimeout = 10.minute

val projectRoot = Paths.get("").toAbsolutePath

Expand Down
15 changes: 9 additions & 6 deletions src/test/scala/afenton/bazel/bsp/LspTestProcess.scala
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,12 @@ case class BspClient(
bspInQ: Queue[IO, String],
counter: Ref[IO, Int]
):
private def sendNotification[A: Encoder](
method: String,
params: A
): IO[Unit] =
val notification = Notification("2.0", method, Some(Encoder[A].apply(params)))
bspInQ.offer(JRpcConsoleCodec.encode(notification, false))

private def sendRequest[A: Encoder, B: Decoder](
method: String,
Expand Down Expand Up @@ -92,9 +98,8 @@ case class BspClient(
def buildShutdown(params: Unit): IO[DeferredSource[IO, Unit]] =
sendRequest("build/shutdown", params)

// TODO: Need to turn this into a notification, not a request
// def buildExit(params: Unit): IO[Unit] =
// sendRequest("build/exit", params)
def buildExit(params: Unit): IO[Unit] =
sendNotification("build/exit", params)

// def workspaceBuildTargets(params: Unit): IO[WorkspaceBuildTargetsResult]

Expand Down Expand Up @@ -261,9 +266,7 @@ case class LspTestProcess(workspaceRoot: Path):
for
d1 <- client.buildShutdown(())
_ <- d1.get
// TODO need to send exit, once that's supported
// d2 <- client.buildExit(())
// _ <- d2.get
_ <- client.buildExit(())
_ <- exitSwitch.complete(Right(()))
yield ()

Expand Down

0 comments on commit de19c5b

Please sign in to comment.