Using spring-amqp with heavy load on RabbitMQ bus, we sometimes get logs from org.springframework.amqp.rabbit.connection.CachingConnectionFactory saying : Channel shutdown: clean channel shutdown; protocol method: #method<channel.close>(reply-code=200, reply-text=NACKS RECEIVED, class-id=0, method-id=0)
Can you explain this log, please, and why is it at ERROR level? Do we have any adjustments to make? Thanks in advance for your answer.
The channel throws an exception if all publisher confirms are not returned with the timeout...
@Override
public void waitForConfirmsOrDie(long timeout)
throws IOException, InterruptedException, TimeoutException
{
try {
if (!waitForConfirms(timeout)) {
close(AMQP.REPLY_SUCCESS, "NACKS RECEIVED", true, null, false);
throw new IOException("nacks received");
}
} catch (TimeoutException e) {
close(AMQP.PRECONDITION_FAILED, "TIMEOUT WAITING FOR ACK");
throw(e);
}
}
The DefaultChannelCloseLogger
will only skip normal closes (200) if the reply text is OK
...
/**
* Return true if the {@link ShutdownSignalException} reason is AMQP.Channel.Close and
* the reply code was AMQP.REPLY_SUCCESS (200) and the text equals "OK".
* @param sig the exception.
* @return true for a normal channel close.
*/
public static boolean isNormalChannelClose(ShutdownSignalException sig) {
Method shutdownReason = sig.getReason();
return isNormalShutdown(sig) ||
(shutdownReason instanceof AMQP.Channel.Close
&& AMQP.REPLY_SUCCESS == ((AMQP.Channel.Close) shutdownReason).getReplyCode()
&& "OK".equals(((AMQP.Channel.Close) shutdownReason).getReplyText()));
}
If you want to ignore these errors, you can configure a custom close exception logger:
/**
* Set the strategy for logging close exceptions; by default, if a channel is closed due to a failed
* passive queue declaration, it is logged at debug level. Normal channel closes (200 OK) are not
* logged. All others are logged at ERROR level (unless access is refused due to an exclusive consumer
* condition, in which case, it is logged at INFO level).
* @param closeExceptionLogger the {@link ConditionalExceptionLogger}.
* @since 1.5
*/
public void setCloseExceptionLogger(ConditionalExceptionLogger closeExceptionLogger) {
Assert.notNull(closeExceptionLogger, "'closeExceptionLogger' cannot be null");
this.closeExceptionLogger = closeExceptionLogger;
if (this.publisherConnectionFactory != null) {
this.publisherConnectionFactory.setCloseExceptionLogger(closeExceptionLogger);
}
}