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 wich 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 copnnects 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;
}
}