Start server if active.json file is removed

If there are two sbt instances and one of them is running a server, the
other instance is presently prevented from ever starting a server. If an
sbt instance is unable to start a local server because of the presence
of another server, we can monitor the active.json file for changes and,
if it is deleted, we can then try again to start a new server instance.
This commit is contained in:
Ethan Atkins 2020-11-02 08:31:36 -08:00
parent 8c3f2a50f7
commit 452c49f84c
1 changed files with 24 additions and 1 deletions

View File

@ -50,6 +50,7 @@ private[sbt] final class CommandExchange {
sys.props get "sbt.server.autostart" forall (_.toLowerCase == "true")
private var server: Option[ServerInstance] = None
private val firstInstance: AtomicBoolean = new AtomicBoolean(true)
private val monitoringActiveJson: AtomicBoolean = new AtomicBoolean(false)
private var consoleChannel: Option[ConsoleChannel] = None
private val commandQueue: LinkedBlockingQueue[Exec] = new LinkedBlockingQueue[Exec]
private val channelBuffer: ListBuffer[CommandChannel] = new ListBuffer()
@ -188,6 +189,7 @@ private[sbt] final class CommandExchange {
lazy val connectionType = s.get(serverConnectionType).getOrElse(ConnectionType.Tcp)
lazy val handlers = s.get(fullServerHandlers).getOrElse(Nil)
lazy val win32Level = s.get(windowsServerSecurityLevel).getOrElse(2)
lazy val portfile = s.baseDir / "project" / "target" / "active.json"
def onIncomingSocket(socket: Socket, instance: ServerInstance): Unit = {
val name = newNetworkName
@ -204,7 +206,6 @@ private[sbt] final class CommandExchange {
subscribe(channel)
}
if (server.isEmpty && firstInstance.get) {
val portfile = s.baseDir / "project" / "target" / "active.json"
val h = Hash.halfHashString(IO.toURI(portfile).toString)
val serverDir =
sys.env get "SBT_GLOBAL_SERVER_DIR" map file getOrElse BuildPaths.getGlobalBase(s) / "server"
@ -231,6 +232,7 @@ private[sbt] final class CommandExchange {
case Some(Success(())) =>
// remember to shutdown only when the server comes up
server = Some(serverInstance)
s.log.info("started sbt server")
case Some(Failure(_: AlreadyRunningException)) =>
s.log.warn(
"sbt server could not start because there's another instance of sbt running on this build."
@ -254,6 +256,27 @@ private[sbt] final class CommandExchange {
s.get(Keys.bootServerSocket).foreach(_.close())
}
if (server.isEmpty && !monitoringActiveJson.get) {
s.get(sbt.nio.Keys.globalFileTreeRepository) match {
case Some(r) =>
r.register(sbt.nio.file.Glob(portfile)) match {
case Right(o) =>
o.addObserver { event =>
if (!event.exists) {
firstInstance.set(true)
monitoringActiveJson.set(false)
// FailureWall is effectively a no-op command that will
// cause shell to re-run which should start the server
commandQueue.add(Exec(BasicCommandStrings.FailureWall, None))
o.close()
}
}
monitoringActiveJson.set(true)
case _ =>
}
case _ =>
}
}
s.remove(Keys.bootServerSocket)
}