Reputation: 1981
I have a monitor service that sends a message to RabbitMQ on application startup, application shutdown and every minute (tick).
The startup and tick events work fine. When the class was originally written the shutdown event also worked.
I am using spring-boot-starter-amqp 1.3.3.RELEASE
The event was fired on the destroy
method of the DisposableBean
interface.
I have also tried implementing ApplicationListener<ContextClosedEvent>
interface and Lifecycle
interface
Both the above methods return:
java.lang.IllegalStateException: The ApplicationContext is closed and the ConnectionFactory can no longer create connections.
I notice there was a bug fix https://jira.spring.io/browse/AMQP-536 which suggests the Lifecycle
interface.
How do I ensure my shutdown event message is sent before the RabbitMQ connection is closed?
EDIT: More info and Latest Code
The application has multiple connection factories to different servers. The Monitor Service connects to the RabbitMQ server via monitorRabbitTemplate
.
The issue seems to be the monitorRabbitTemplate
connection Factory gets the Lifecycle/Shutdown/Dispose event before the MonitorService
.
Latest code (using Lifecycle
instead of ApplicationListener<ContextClosedEvent>
and DisposableBean
):
@Component
public class MonitorServiceImpl implements MonitorService , Lifecycle {
private static final Logger LOGGER = LoggerFactory.getLogger(MonitorServiceImpl.class);
private final RabbitTemplate monitorRabbitTemplate;
private final String queueName;
private final Gson gson = new Gson();
@Autowired
public MonitorServiceImpl(@Qualifier("monitorRabbitTemplate") final RabbitTemplate monitorRabbitTemplate,
@Value("${monitor.rabbitmq.queue.name:monitor}") final String queueName) {
this.monitorRabbitTemplate = monitorRabbitTemplate;
this.queueName = queueName;
}
@Scheduled(fixedDelay = 60000)
public void tick() {
try {
send(new Monitor(Status.INFO, "I am here"));
} catch (final Exception e) {
LOGGER.error("FAILED TO SEND TICK EVENT", e);
}
}
@Override
public void send(final Monitor monitor) {
try {
final Message message = MessageBuilder.withBody(gson.toJson(monitor).getBytes())
.setContentType("application/json").setPriority(0).setDeliveryMode(MessageDeliveryMode.PERSISTENT)
.build();
monitorRabbitTemplate.send(queueName, message);
} catch (final Exception e) {
LOGGER.error("FAILED TO SEND MONITOR EVENT", e);
LOGGER.error("FAILED TO SEND MONITOR EVENT to {}:{}", monitorRabbitTemplate.getConnectionFactory()
.getHost(), monitorRabbitTemplate.getConnectionFactory().getPort());
}
}
@Override
public void start() {
try {
send(new Monitor(Status.STARTING, "Application starting up..."));
} catch (final Exception e) {
LOGGER.error("FAILED TO SEND STARTUP EVENT", e);
}
}
@Override
public void stop() {
try {
send(new Monitor(Status.TERMINATING, "Application shutdown..."));
} catch (final Exception e) {
LOGGER.error("FAILED TO SEND SHUTDOWN EVENT", e);
}
}
@Override
public boolean isRunning() {
return true;
}
}
Upvotes: 5
Views: 2802
Reputation: 5369
Maybe you could share some code/build configuration? Because listening to ContextClosedEvent
and implementing Lifecycle
both work for me.
Here's my application:
@SpringBootApplication
public class SpringRabbitmqDemoApplication {
@Component
public static class Whatever implements Lifecycle {
private final RabbitTemplate template;
@Autowired
public Whatever(RabbitTemplate template) {
this.template = template;
}
@EventListener
public void event(ContextClosedEvent event) throws Exception {
sendMessage(event.toString());
}
private void sendMessage(String message) {
template.convertAndSend("", "queue", message);
System.out.println("Sent event " + message);
}
@Override
public void start() {
sendMessage("start");
}
@Override
public void stop() {
sendMessage("stop");
}
@Override
public boolean isRunning() {
return true;
}
}
public static void main(String[] args) {
SpringApplication.run(SpringRabbitmqDemoApplication.class, args);
}
}
And my pom.xml file:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>spring-rabbitmq-demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>spring-rabbitmq-demo</name>
<description>Demo project for Spring Boot RabbitMQ</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.3.3.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Here's the output I get:
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v1.3.3.RELEASE)
2016-07-21 17:45:24.984 INFO 77845 --- [ main] c.example.SpringRabbitmqDemoApplication : Starting SpringRabbitmqDemoApplication on mmilivojevic-hal9000 with PID 77845 (started by mmilivojevic in /Volumes/Macintosh HD/springrabbitmqdemo)
2016-07-21 17:45:24.990 INFO 77845 --- [ main] c.example.SpringRabbitmqDemoApplication : No active profile set, falling back to default profiles: default
2016-07-21 17:45:25.092 INFO 77845 --- [ main] s.c.a.AnnotationConfigApplicationContext : Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@27d415d9: startup date [Thu Jul 21 17:45:25 CEST 2016]; root of context hierarchy
2016-07-21 17:45:26.746 INFO 77845 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'org.springframework.amqp.rabbit.annotation.RabbitBootstrapConfiguration' of type [class org.springframework.amqp.rabbit.annotation.RabbitBootstrapConfiguration$$EnhancerBySpringCGLIB$$2cf55fc7] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2016-07-21 17:45:27.620 INFO 77845 --- [ main] o.s.j.e.a.AnnotationMBeanExporter : Registering beans for JMX exposure on startup
2016-07-21 17:45:27.636 INFO 77845 --- [ main] o.s.c.support.DefaultLifecycleProcessor : Starting beans in phase -2147482648
2016-07-21 17:45:27.637 INFO 77845 --- [ main] o.s.c.support.DefaultLifecycleProcessor : Starting beans in phase 2147483647
2016-07-21 17:45:27.661 INFO 77845 --- [ main] c.example.SpringRabbitmqDemoApplication : Started SpringRabbitmqDemoApplication in 3.456 seconds (JVM running for 4.288)
2016-07-21 17:45:27.662 INFO 77845 --- [ Thread-1] s.c.a.AnnotationConfigApplicationContext : Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@27d415d9: startup date [Thu Jul 21 17:45:25 CEST 2016]; root of context hierarchy
2016-07-21 17:45:27.785 INFO 77845 --- [ Thread-1] o.s.a.r.c.CachingConnectionFactory : Created new connection: SimpleConnection@7ff53a50 [delegate=amqp://[email protected]:5672/]
Sent event org.springframework.context.event.ContextClosedEvent[source=org.springframework.context.annotation.AnnotationConfigApplicationContext@27d415d9: startup date [Thu Jul 21 17:45:25 CEST 2016]; root of context hierarchy]
2016-07-21 17:45:27.829 INFO 77845 --- [ Thread-1] o.s.c.support.DefaultLifecycleProcessor : Stopping beans in phase 2147483647
2016-07-21 17:45:27.830 INFO 77845 --- [ Thread-1] o.s.c.support.DefaultLifecycleProcessor : Stopping beans in phase 0
Sent event stop
2016-07-21 17:45:27.831 INFO 77845 --- [ Thread-1] o.s.c.support.DefaultLifecycleProcessor : Stopping beans in phase -2147482648
2016-07-21 17:45:27.834 INFO 77845 --- [ Thread-1] o.s.j.e.a.AnnotationMBeanExporter : Unregistering JMX-exposed beans on shutdown
Upvotes: 3