I'm running multiple tests with spring-amqp, spring-rabbit. My Maven parent is spring-boot-starter-parent:1.2.3.RELEASE which pulls:
spring-rabbit:1.4.3.RELEASE
spring-amqp:1.4.3.RELEASE
amqp-client:3.4.2
At a certain point one of the tests fails with this error and I don't see the reason:
Executing callback on RabbitMQ Channel: Cached Rabbit Channel: AMQChannel(amqp://[email protected]:5672/,2119)
Channel shutdown: channel error; protocol method: #method<channel.close>(reply-code=406, reply-text=PRECONDITION_FAILED - reply consumer already set, class-id=60, method-id=20)
Detected closed channel on exception. Re-initializing: null
If I change to spring-boot-starter-parent:1.3.1.RELEASE all tests are passed.
Digging down in the different versions, it seems I can still reproduce the failed test with
spring-rabbit:1.5.0.M1
spring-amqp:1.5.0.M1
amqp-client:3.5.5
but all tests are passing with
spring-rabbit:1.5.0.RELEASE
spring-amqp:1.5.0.RELEASE
amqp-client:3.5.5
Is there any relevant change between 1.5.0.M1 and 1.5.0.RELEASE that could answer this? I tried to browse GitHub compare but didn't help.
1st update:
I could narrow down the issue. In the tests I call sendAndReceive() to a queue inside a HystrixCommand (from Netflix). This HystrixCommand uses a smaller (2s) timeout then the default reply timeout (5s) in RabbitTemplate.
A service is listening on that declared queue and returns the answer.
I have a certain test to do a sendAndReceive() to a non-existing queue. When that special test is executed the HystrixCommand times out.
The next test executing sendAndReceive() to the declared queue gives the channel error.
@SpringBootApplication
public class SpringAmqpTestApplication implements CommandLineRunner {
public static final String QUEUE_NAME = "Spring-AMQP-Test";
private static final String NONEXISTENT_QUEUE_NAME = UUID.randomUUID().toString() + "@" + System.currentTimeMillis();
public static void main( String[] args ) {
SpringApplication.run( SpringAmqpTestApplication.class, args );
}
@Autowired
AmqpTemplate amqpTemplate;
@Override
public void run( String... args ) throws Exception {
sendAndReceive( QUEUE_NAME );
sendAndReceive( NONEXISTENT_QUEUE_NAME );
sendAndReceive( QUEUE_NAME );
}
private void sendAndReceive( String routingKey ) {
CustomHystrixCommand customHystrixCommand = new CustomHystrixCommand( amqpTemplate, routingKey );
String answer = customHystrixCommand.execute();
System.err.println( "< sendAndReceive(): " + answer );
}
}
My HystrixCommand is fairly simple:
public class CustomHystrixCommand extends HystrixCommand<String> {
private String routingKey;
AmqpTemplate amqpTemplate;
public CustomHystrixCommand( AmqpTemplate amqpTemplate, String routingKey ) {
super( HystrixCommandGroupKey.Factory.asKey( "" ), 2000 );
this.amqpTemplate = amqpTemplate;
this.routingKey = routingKey;
}
@Override
protected String run() throws Exception {
String request = UUID.randomUUID().toString();
MessageProperties messageProperties = new MessageProperties();
Message message = new Message( request.getBytes(), messageProperties );
Message answer = amqpTemplate.sendAndReceive( "", routingKey, message );
return "OK answer";
}
@Override
protected String getFallback() {
return "getFallback()";
}
}
With spring-boot-starter-parent:1.2.3.RELEASE my logs are:
< sendAndReceive(): OK answer
< sendAndReceive(): getFallback()
2016-01-27 11:47:42.266 ERROR 15007 --- [pool-1-thread-1] o.s.a.r.c.CachingConnectionFactory : Channel shutdown: channel error; protocol method: #method<channel.close>(reply-code=406, reply-text=PRECONDITION_FAILED - reply consumer already set, class-id=60, method-id=20)
< sendAndReceive(): getFallback()
while with spring-boot-starter-parent:1.3.1.RELEASE:
< sendAndReceive(): OK answer
< sendAndReceive(): getFallback()
< sendAndReceive(): OK answer
Thanks for any help / explanation.
spring-amqp:1.4.3.RELEASE
, so we can play locally and reproduce. From other side not sure if it makes sense to fight, when you confirm that everything works well with 1.5 or later. - Artem Bilan