From ac96d95f97c3298818a23c40e517815f232f0a2f Mon Sep 17 00:00:00 2001 From: Gary Russell Date: Thu, 28 Feb 2013 22:42:32 -0500 Subject: [PATCH] AMQP-281 Shut Down Timer in AMQP Appender When using the AMQP log4j appender, it can cause orphaned daemon threads when undeploying WARs. Also, when exiting main() methods, apps should call Log4jConfigurer.shutdownLogging(); in a finally block to destroy() the connetion factory (releasing threads used by the rabbit client). --- .../amqp/rabbit/log4j/AmqpAppender.java | 7 ++++--- .../rabbit/log4j/AmqpAppenderIntegrationTests.java | 12 ++++++++++++ 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/log4j/AmqpAppender.java b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/log4j/AmqpAppender.java index 3218349d..74f6ec65 100644 --- a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/log4j/AmqpAppender.java +++ b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/log4j/AmqpAppender.java @@ -153,7 +153,7 @@ public class AmqpAppender extends AppenderSkeleton { /** * Whether or not we've tried to declare this exchange yet. */ - private AtomicBoolean exchangeDeclared = new AtomicBoolean(false); + private final AtomicBoolean exchangeDeclared = new AtomicBoolean(false); /** * Configuration arbitrary application ID. @@ -163,7 +163,7 @@ public class AmqpAppender extends AppenderSkeleton { /** * Where LoggingEvents are queued to send. */ - private LinkedBlockingQueue events = new LinkedBlockingQueue(); + private final LinkedBlockingQueue events = new LinkedBlockingQueue(); /** * The pool of senders. @@ -183,7 +183,7 @@ public class AmqpAppender extends AppenderSkeleton { /** * Retries are delayed like: N ^ log(N), where N is the retry number. */ - private Timer retryTimer = new Timer("log-event-retry-delay", true); + private final Timer retryTimer = new Timer("log-event-retry-delay", true); /** * RabbitMQ ConnectionFactory. @@ -448,6 +448,7 @@ public class AmqpAppender extends AppenderSkeleton { if (null != connectionFactory) { connectionFactory.destroy(); } + retryTimer.cancel(); } public boolean requiresLayout() { diff --git a/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/log4j/AmqpAppenderIntegrationTests.java b/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/log4j/AmqpAppenderIntegrationTests.java index b910aa55..8485ac2b 100644 --- a/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/log4j/AmqpAppenderIntegrationTests.java +++ b/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/log4j/AmqpAppenderIntegrationTests.java @@ -19,6 +19,8 @@ import static org.junit.Assert.assertTrue; import java.util.concurrent.TimeUnit; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; import org.apache.log4j.Logger; import org.apache.log4j.MDC; import org.junit.After; @@ -104,4 +106,14 @@ public class AmqpAppenderIntegrationTests { assertEquals(propertyValue, messageProperties.getHeaders().get(propertyName)); } + /* + * When running as main(); should shutdown cleanly. + */ + public static void main(String[] args) throws Exception { + Log4jConfigurer.initLogging("classpath:log4j-amqp.properties"); + Log logger = LogFactory.getLog(AmqpAppenderIntegrationTests.class); + logger.info("foo"); + Thread.sleep(1000); + Log4jConfigurer.shutdownLogging(); + } }