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 def out: ConsoleOut
} }
private[sbt] object Properties { private[sbt] object Properties {
def from(terminal: Terminal): Properties = new Properties { def from(terminal: Terminal): Properties =
override def isAnsiSupported: Boolean = terminal.isAnsiSupported from(ConsoleOut.terminalOut(terminal), terminal.isAnsiSupported, terminal.isColorEnabled)
override def isColorEnabled: Boolean = terminal.isColorEnabled
override def out = ConsoleOut.terminalOut(terminal) def safelyFrom(terminal: Terminal): Properties =
} from(ConsoleOut.safeTerminalOut(terminal), terminal.isAnsiSupported, terminal.isColorEnabled)
def from(o: ConsoleOut, ansi: Boolean, color: Boolean): Properties = new Properties { def from(o: ConsoleOut, ansi: Boolean, color: Boolean): Properties = new Properties {
override def isAnsiSupported: Boolean = ansi override def isAnsiSupported: Boolean = ansi
override def isColorEnabled: Boolean = color override def isColorEnabled: Boolean = color
@ -246,6 +247,18 @@ object ConsoleAppender {
new ConsoleAppender(name, Properties.from(terminal), noSuppressedMessage) 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`. * A new `ConsoleAppender` identified by `name`, and that writes to `out`.
* *

View File

@ -8,6 +8,7 @@
package sbt.internal.util package sbt.internal.util
import java.io.{ BufferedWriter, PrintStream, PrintWriter } import java.io.{ BufferedWriter, PrintStream, PrintWriter }
import java.nio.channels.ClosedChannelException
import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.atomic.AtomicReference import java.util.concurrent.atomic.AtomicReference
@ -90,6 +91,26 @@ object ConsoleOut {
override def toString: String = s"TerminalOut" 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] private[this] val consoleOutPerTerminal = new ConcurrentHashMap[Terminal, ConsoleOut]
def terminalOut(terminal: Terminal): ConsoleOut = consoleOutPerTerminal.get(terminal) match { def terminalOut(terminal: Terminal): ConsoleOut = consoleOutPerTerminal.get(terminal) match {
case null => case null =>

View File

@ -149,7 +149,7 @@ object LogManager {
task: ScopedKey[_], task: ScopedKey[_],
context: LoggerContext context: LoggerContext
): ManagedLogger = { ): 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) LogManager.backgroundLog(data, state, task, console, relay(()), context)
} }
} }