Skip to content

Commit 3be802f

Browse files
garyrussellartembilan
authored andcommitted
GH-1225: Fix Log4j2 Appender Termination
Replaces #1225 `manager.stop()` was never called to destroy the connection factory, preventing JVM exit. Also protect for re-connecting after stop (both appenders). Tested with a Spring Boot application. **cherry-pick to 2.2.x, 2.1.x, 1.7.x** # Conflicts: # spring-rabbit/src/main/java/org/springframework/amqp/rabbit/logback/AmqpAppender.java
1 parent 70dfc9e commit 3be802f

File tree

2 files changed

+24
-2
lines changed

2 files changed

+24
-2
lines changed

spring-rabbit/src/main/java/org/springframework/amqp/rabbit/log4j2/AmqpAppender.java

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
import org.apache.logging.log4j.core.layout.PatternLayout;
5252
import org.apache.logging.log4j.core.util.Integers;
5353

54+
import org.springframework.amqp.AmqpApplicationContextClosedException;
5455
import org.springframework.amqp.AmqpException;
5556
import org.springframework.amqp.core.DirectExchange;
5657
import org.springframework.amqp.core.Exchange;
@@ -70,6 +71,9 @@
7071
import org.springframework.amqp.rabbit.core.RabbitTemplate;
7172
import org.springframework.amqp.rabbit.support.RabbitExceptionTranslator;
7273
import org.springframework.amqp.utils.JavaUtils;
74+
import org.springframework.context.ApplicationContext;
75+
import org.springframework.context.event.ContextClosedEvent;
76+
import org.springframework.context.support.GenericApplicationContext;
7377
import org.springframework.core.io.Resource;
7478
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
7579
import org.springframework.retry.RetryPolicy;
@@ -360,6 +364,9 @@ protected void doSend(Event event, LogEvent logEvent, MessageProperties amqpProp
360364
message = postProcessMessageBeforeSend(message, event);
361365
this.rabbitTemplate.send(this.manager.exchangeName, routingKey, message);
362366
}
367+
catch (AmqpApplicationContextClosedException e) {
368+
getHandler().error("Could not send log message " + logEvent.getMessage() + " appender is stopped");
369+
}
363370
catch (AmqpException e) {
364371
int retries = event.incrementRetries();
365372
if (this.manager.async && retries < this.manager.maxSenderRetries) {
@@ -386,7 +393,7 @@ public void run() {
386393
@Override
387394
protected boolean stop(long timeout, TimeUnit timeUnit, boolean changeLifeCycleState) {
388395
boolean stopped = super.stop(timeout, timeUnit, changeLifeCycleState);
389-
return stopped || this.manager.stop(timeout, timeUnit);
396+
return this.manager.stop(timeout, timeUnit) || stopped;
390397
}
391398

392399
/**
@@ -455,6 +462,8 @@ protected static class AmqpManager extends AbstractManager {
455462

456463
private static final int DEFAULT_MAX_SENDER_RETRIES = 30;
457464

465+
private final ApplicationContext context = new GenericApplicationContext();
466+
458467
/**
459468
* True to send events on separate threads.
460469
*/
@@ -662,6 +671,7 @@ private boolean activateOptions() {
662671
.withNoConsoleNoAnsi(true)
663672
.build();
664673
this.connectionFactory = new CachingConnectionFactory(rabbitConnectionFactory);
674+
this.connectionFactory.setApplicationContext(this.context);
665675
if (StringUtils.hasText(this.connectionName)) {
666676
this.connectionFactory.setConnectionNameStrategy(cf -> this.connectionName);
667677
}
@@ -751,6 +761,7 @@ protected boolean releaseSub(long timeout, TimeUnit timeUnit) {
751761
this.retryTimer.cancel();
752762
this.senderPool.shutdownNow();
753763
this.connectionFactory.destroy();
764+
this.connectionFactory.onApplicationEvent(new ContextClosedEvent(this.context));
754765
try {
755766
return this.senderPool.awaitTermination(timeout, timeUnit);
756767
}

spring-rabbit/src/main/java/org/springframework/amqp/rabbit/logback/AmqpAppender.java

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2014-2018 the original author or authors.
2+
* Copyright 2014-2020 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -32,6 +32,7 @@
3232
import java.util.concurrent.atomic.AtomicBoolean;
3333
import java.util.concurrent.atomic.AtomicInteger;
3434

35+
import org.springframework.amqp.AmqpApplicationContextClosedException;
3536
import org.springframework.amqp.AmqpException;
3637
import org.springframework.amqp.core.DirectExchange;
3738
import org.springframework.amqp.core.Exchange;
@@ -51,6 +52,9 @@
5152
import org.springframework.amqp.rabbit.core.RabbitTemplate;
5253
import org.springframework.amqp.rabbit.support.RabbitExceptionTranslator;
5354
import org.springframework.amqp.utils.JavaUtils;
55+
import org.springframework.context.ApplicationContext;
56+
import org.springframework.context.event.ContextClosedEvent;
57+
import org.springframework.context.support.GenericApplicationContext;
5458
import org.springframework.core.io.Resource;
5559
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
5660
import org.springframework.util.StringUtils;
@@ -121,6 +125,8 @@ public class AmqpAppender extends AppenderBase<ILoggingEvent> {
121125
*/
122126
public static final String THREAD_NAME = "thread";
123127

128+
private final ApplicationContext context = new GenericApplicationContext();
129+
124130
/**
125131
* Name of the exchange to publish log events to.
126132
*/
@@ -683,6 +689,7 @@ public void start() {
683689
this.locationLayout.setContext(getContext());
684690
this.locationLayout.start();
685691
this.connectionFactory = new CachingConnectionFactory(rabbitConnectionFactory);
692+
this.connectionFactory.setApplicationContext(this.context);
686693
if (StringUtils.hasText(this.connectionName)) {
687694
this.connectionFactory.setConnectionNameStrategy(cf -> this.connectionName);
688695
}
@@ -798,6 +805,7 @@ public void stop() {
798805
}
799806
if (null != this.connectionFactory) {
800807
this.connectionFactory.destroy();
808+
this.connectionFactory.onApplicationEvent(new ContextClosedEvent(this.context));
801809
}
802810
this.retryTimer.cancel();
803811
this.routingKeyLayout.stop();
@@ -957,6 +965,9 @@ private void doSend(RabbitTemplate rabbitTemplate, final Event event, ILoggingEv
957965
message = postProcessMessageBeforeSend(message, event);
958966
rabbitTemplate.send(AmqpAppender.this.exchangeName, routingKey, message);
959967
}
968+
catch (AmqpApplicationContextClosedException e) {
969+
addError("Could not send log message " + logEvent.getMessage() + " appender is stopped");
970+
}
960971
catch (AmqpException e) {
961972
int retries = event.incrementRetries();
962973
if (retries < AmqpAppender.this.maxSenderRetries) {

0 commit comments

Comments
 (0)