diff --git a/subprojects/logging/src/main/java/org/gradle/internal/logging/console/ThrottlingOutputEventListener.java b/subprojects/logging/src/main/java/org/gradle/internal/logging/console/ThrottlingOutputEventListener.java index 72db322be3f4..51854a42c3d5 100644 --- a/subprojects/logging/src/main/java/org/gradle/internal/logging/console/ThrottlingOutputEventListener.java +++ b/subprojects/logging/src/main/java/org/gradle/internal/logging/console/ThrottlingOutputEventListener.java @@ -22,6 +22,8 @@ import org.gradle.internal.logging.events.OutputEventListener; import org.gradle.internal.logging.events.UpdateNowEvent; import org.gradle.internal.time.Clock; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.util.ArrayList; import java.util.List; @@ -33,6 +35,8 @@ * Queue output events to be forwarded and schedule flush when time passed or if end of build is signalled. */ public class ThrottlingOutputEventListener implements OutputEventListener { + private static final Logger LOGGER = LoggerFactory.getLogger(ThrottlingOutputEventListener.class); + private final OutputEventListener listener; private final ScheduledExecutorService executor; @@ -58,7 +62,13 @@ private void scheduleUpdateNow() { executor.scheduleAtFixedRate(new Runnable() { @Override public void run() { - onOutput(new UpdateNowEvent(clock.getCurrentTime())); + try { + onOutput(new UpdateNowEvent(clock.getCurrentTime())); + } catch (Throwable t) { + // this class is used as task in a scheduled executor service, so it must not throw any throwable, + // otherwise the further invocations of this task get automatically and silently cancelled + LOGGER.debug("Exception while displaying output", t); + } } }, throttleMs, throttleMs, TimeUnit.MILLISECONDS); } diff --git a/subprojects/logging/src/test/groovy/org/gradle/internal/logging/console/ThrottlingOutputEventListenerTest.groovy b/subprojects/logging/src/test/groovy/org/gradle/internal/logging/console/ThrottlingOutputEventListenerTest.groovy index 1501e0ff3172..fb8dfffe011c 100644 --- a/subprojects/logging/src/test/groovy/org/gradle/internal/logging/console/ThrottlingOutputEventListenerTest.groovy +++ b/subprojects/logging/src/test/groovy/org/gradle/internal/logging/console/ThrottlingOutputEventListenerTest.groovy @@ -20,6 +20,7 @@ import org.gradle.internal.logging.events.EndOutputEvent import org.gradle.internal.logging.events.FlushOutputEvent import org.gradle.internal.logging.events.OutputEventListener import org.gradle.internal.logging.events.UpdateNowEvent +import org.gradle.internal.time.Clock import org.gradle.internal.time.MockClock import org.gradle.util.internal.MockExecutor import spock.lang.Subject @@ -155,4 +156,24 @@ class ThrottlingOutputEventListenerTest extends OutputSpecification { then: executor.isShutdown() } + + def "throwables are not propagated out of the run method of the output loop"() { + given: + def executor = new MockExecutor() + new ThrottlingOutputEventListener(listener, 100, executor, Mock(Clock)) + def checks = executor.shutdownNow() + + when: + checks*.run() + + then: + 1 * _ >> { throw throwable } + noExceptionThrown() + + where: + throwable | _ + new Exception() | _ + new RuntimeException() | _ + new Error() | _ + } }