1

I'm trying to migrate from camel 3.x to camel 4.x version, so I need to migrate from the rabbitmq component to the replacing one spring-rabbitmq. With rabbitmq component I was using the declare option to let Camel automatically create and bind queues and exchanges, now I'm looking for equivalent options in the spring-rabbitmq component:

From the documentation it looks like this is possible : https://camel.apache.org/components/3.20.x/spring-rabbitmq-component.html#_auto_declare_exchanges_queues_and_bindings :

Before you can send or receive messages from RabbitMQ, then exchanges, queues and bindings must be setup first.

In development mode it may be desirable to let Camel automatic do this. You can enable this by setting autoDeclare=true on the SpringRabbitMQComponent.

Then Spring RabbitMQ will automatic necessary declare the elements and setup the binding between the exchange, queue and routing keys.

So I've configured the camel.component.spring-rabbitmq.auto-declare property to true in my application.properties : but it seems that this affects only the rabbitmq consumer endpoints, not the producer.

Using this simple route:

<route id="receive-send-rabbitmq">
    <from uri="spring-rabbitmq:in-exchange?queues=queue-in"/>
    <log message="message received" />    
    <to uri="spring-rabbitmq:out-exchange"/>
</route>

The in-exchange and queue-in objects are properly auto-declared by Camel when starting the route, messages are properly received. But the sending part is failing due to exchange out-exchange not available. Stack trace :

2023-07-10T11:54:12.094+02:00 DEBUG 3796 --- [pool-2-thread-5] o.s.amqp.rabbit.core.RabbitTemplate      : Publishing message [(Body:'[B@149e60f3(byte[3])' MessageProperties [headers={}, contentType=application/octet-stream, contentLength=3, deliveryMode=PERSISTENT, priority=0, deliveryTag=0])] on exchange [out-exchange], routingKey = []
2023-07-10T11:54:12.099+02:00  INFO 3796 --- [ 127.0.0.1:5672] com.rabbitmq.client.impl.AMQConnection   : Received a frame on an unknown channel, ignoring it
2023-07-10T11:54:12.099+02:00 DEBUG 3796 --- [pool-2-thread-5] o.s.amqp.rabbit.connection.RabbitUtils   : Unexpected exception on closing RabbitMQ Channel

com.rabbitmq.client.ShutdownSignalException: channel error; protocol method: #method<channel.close>(reply-code=404, reply-text=NOT_FOUND - no exchange 'out-exchange' in vhost '/', class-id=60, method-id=40)
    at com.rabbitmq.utility.ValueOrException.getValue(ValueOrException.java:66)
    at com.rabbitmq.utility.BlockingValueOrException.uninterruptibleGetValue(BlockingValueOrException.java:36)
    at com.rabbitmq.client.impl.AMQChannel$BlockingRpcContinuation.getReply(AMQChannel.java:502)

    at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
    at java.base/java.lang.Thread.run(Thread.java:833)
Caused by: com.rabbitmq.client.ShutdownSignalException: channel error; protocol method: #method<channel.close>(reply-code=404, reply-text=NOT_FOUND - no exchange 'out-exchange' in vhost '/', class-id=60, method-id=40)
    at com.rabbitmq.client.impl.ChannelN.asyncShutdown(ChannelN.java:517)
    at com.rabbitmq.client.impl.ChannelN.processAsync(ChannelN.java:341)
    at com.rabbitmq.client.impl.AMQChannel.handleCompleteInboundCommand(AMQChannel.java:182)
    at com.rabbitmq.client.impl.AMQChannel.handleFrame(AMQChannel.java:114)
    at com.rabbitmq.client.impl.AMQConnection.readFrame(AMQConnection.java:743)
    at com.rabbitmq.client.impl.AMQConnection.access$300(AMQConnection.java:47)
    at com.rabbitmq.client.impl.AMQConnection$MainLoop.run(AMQConnection.java:670)
    ... 1 common frames omitted

I know I could declare these exchange using the RabbitAdmin but I don't want to handle this manually in my application code, the routes delivered as XML files in a dedicated folder, loaded dynamically by the application at startup.

Using Camel 4.0.0-rc1 with Springboot 3.1.1

M.Ricciuti
  • 11,070
  • 2
  • 34
  • 54

1 Answers1

1

Simply because this component option is only for consumer endpoints as clearly stated in the documentation, I quote:

Specifies whether the consumer should auto declare binding between exchange, queue and routing key when starting. Enabling this can be good for development to make it easy to standup exchanges, queues and bindings on the broker.

For a producer endpoint, you will need to create it manually by declaring your Queue as a regular bean, Spring will automatically create the Queue for you.

@Bean
public Queue myDurableQueue() {
    // This queue has the following properties:
    // name: my_durable
    // durable: true
    // exclusive: false
    // auto_delete: false
    return new Queue("my_durable", true, false, false);
}

See this answer for more details.

Nicolas Filotto
  • 43,537
  • 11
  • 94
  • 122
  • thanks your your answer. like I said, I cannot create exchange/queues from code. the property `autoDeclare` is indeed marked as 'Consummer only', but there is a section "Auto declare exchanges.." in the documentation that let us think it's possible for producers also : "Before you can **send** or receive messages from RabbitMQ, then exchanges, queues and bindings must be setup first." that's why I ask if this is really possible using component/endpoint properties – M.Ricciuti Jul 10 '23 at 18:28
  • I agree that it is misleading but I've just re-checked the code and I can confirm that it is only for consumers. Check by yourself https://github.com/search?q=repo%3Aapache%2Fcamel%20isAutoDeclare&type=code – Nicolas Filotto Jul 10 '23 at 19:18
  • yep I also checked the code and seen that `autoDeclare` is only used in the Consumer endpoint side. It could also be used in producer side since it's a Component-level property, I guess I should create an improvement request. this is quite annoying since we are forced to migrate to this component when upgrading to camel 4.x, we are losing some useful feature from the old `rabbitmq` component.. I'll wait some days before accepting your answer, hopefully somebody will come with some other idea to make this work ;) tks again – M.Ricciuti Jul 10 '23 at 19:59
  • even the sample project brings confusion: `spring-rabbitmq` is used as producer endpoint but no configuration is done to pre-create the exchange, except the `camel.component.spring-rabbitmq.auto-declare = true` in application.properties. (see https://github.com/apache/camel-spring-boot-examples/blob/main/rabbitmq/src/main/java/sample/camel/SampleCamelRouter.java ) I guess this sample cannot work neither (could not test it myself) – M.Ricciuti Jul 10 '23 at 20:05