Catch ClosedChannelException in background job logger

We want the background job to stay alive even if its terminal
has been closed and we cannot write to it anymore
This commit is contained in:
Adrien Piquerez 2022-08-05 14:45:38 +02:00
parent 592086b889
commit 634e8799e7
3 changed files with 40 additions and 6 deletions

View File

@ -126,11 +126,12 @@ object ConsoleAppender {
def out: ConsoleOut
}
private[sbt] object Properties {
def from(terminal: Terminal): Properties = new Properties {
override def isAnsiSupported: Boolean = terminal.isAnsiSupported
override def isColorEnabled: Boolean = terminal.isColorEnabled
override def out = ConsoleOut.terminalOut(terminal)
}
def from(terminal: Terminal): Properties =
from(ConsoleOut.terminalOut(terminal), terminal.isAnsiSupported, terminal.isColorEnabled)
def safelyFrom(terminal: Terminal): Properties =
from(ConsoleOut.safeTerminalOut(terminal), terminal.isAnsiSupported, terminal.isColorEnabled)
def from(o: ConsoleOut, ansi: Boolean, color: Boolean): Properties = new Properties {
override def isAnsiSupported: Boolean = ansi
override def isColorEnabled: Boolean = color
@ -246,6 +247,18 @@ object ConsoleAppender {
new ConsoleAppender(name, Properties.from(terminal), noSuppressedMessage)
}
/**
* A new `ConsoleAppender` identified by `name`, and that writes to `terminal`.
* Printing to this Appender will not throw if the Terminal has been closed.
*
* @param name An identifier for the `ConsoleAppender`.
* @param terminal The terminal to which this appender corresponds
* @return A new `ConsoleAppender` that writes to `terminal`.
*/
def safe(name: String, terminal: Terminal): Appender = {
new ConsoleAppender(name, Properties.safelyFrom(terminal), noSuppressedMessage)
}
/**
* A new `ConsoleAppender` identified by `name`, and that writes to `out`.
*

View File

@ -8,6 +8,7 @@
package sbt.internal.util
import java.io.{ BufferedWriter, PrintStream, PrintWriter }
import java.nio.channels.ClosedChannelException
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.atomic.AtomicReference
@ -90,6 +91,26 @@ object ConsoleOut {
override def toString: String = s"TerminalOut"
}
/** Same as terminalOut but it catches and ignores the ClosedChannelException
*/
def safeTerminalOut(terminal: Terminal): ConsoleOut = {
val out = terminalOut(terminal)
new ConsoleOut {
override val lockObject: AnyRef = terminal
override def print(s: String): Unit = catchException(out.print(s))
override def println(s: String): Unit = catchException(out.println(s))
override def println(): Unit = catchException(out.println())
override def flush(): Unit = catchException(out.flush)
override def toString: String = s"SafeTerminalOut($terminal)"
private def catchException(f: => Unit): Unit = {
try f
catch {
case _: ClosedChannelException => ()
}
}
}
}
private[this] val consoleOutPerTerminal = new ConcurrentHashMap[Terminal, ConsoleOut]
def terminalOut(terminal: Terminal): ConsoleOut = consoleOutPerTerminal.get(terminal) match {
case null =>

View File

@ -149,7 +149,7 @@ object LogManager {
task: ScopedKey[_],
context: LoggerContext
): ManagedLogger = {
val console = ConsoleAppender("bg-" + ConsoleAppender.generateName(), ITerminal.current)
val console = ConsoleAppender.safe("bg-" + ConsoleAppender.generateName(), ITerminal.current)
LogManager.backgroundLog(data, state, task, console, relay(()), context)
}
}