Discussed in https://github.com/spring-projects/spring-amqp/discussions/2918
Comment From: csp1992
Hello, I have the same question. There is a official support of amqp 1.0 in spring boot 3?. Any plans of support in this library?
Comment From: artembilan
According to some resources in the Internet we can use JMS auto-configuration in Spring Boot to talk to AMQP 1.0 protocol: https://github.com/amqphub/amqp-10-jms-spring-boot/tree/main/amqp-10-jms-spring-boot-examples.
We don't deny this issue since it would bring a Spring-friendly API over the mentioned rabbitmq-amqp-java-client
library.
Comment From: JimmyWang6
Hi @artembilan, as mention above, I am willing to handle this issue. Do you know if this issue already started?
Comment From: artembilan
Yes, my plan is to start looking into this from next Monday. However you are free to share your vision for this new module:
- What its name?
- How do we manage connection(s)?
- Do you foresee
Amqp10Template
(similar toRabbitTemplate
) implementation? - What is your thought about
@RabbitListener
support? Or we might have an@Amqp10Listener
instead?
I'm opened for any suggestions
Thank you!
Comment From: artembilan
OK. I have started working on this.
So far I have:
1. Module name is spring-rabbitmq-client
- we kinda anticipate that this one would be a default in the future with slow 0.9.1
support sunset.
2. I wrote AmqpConnectionFactoryBean
to manage AMQP connection object in Spring manner. This is the most important and shared component between the rest of the API.
3. The RabbitAmqpAdmin
- similar to RabbitAdmin
, but with the logic based on the AMQP 1.0 client. We cannot live without topology, so it is better to have it automatically initialized from respective Declarable
beans like we do for 0.9.1
support.
4. Have started RabbitAmqpTemplate
for the Spring-friendly Publisher
API.
Wanted to push and share already, but stuck with so much code to do. Therefore expect something from me in the nearest future. Maybe tomorrow/after tomorrow.
Comment From: making
I'm keeping an eye on this effort.
It looks like Quarkus already supports AMQP 1.0. https://quarkus.io/guides/amqp-reference
I was hoping this client could be used to access other AMQP 1.0-enabled products, such as Azure Service Bus. Is that out of scope? RabbitAmqpTemplate
sounds like it's for RabbitMQ.
Comment From: artembilan
That’s correct, @making . This module is based on the RabbitMQ Java client for only RabbitMQ AMQP 1.0 support. There is no guarantee that it may work with other AMQP 1.0 providers.
We always recommended to use JMS API to communicate with AMQP 1.0 brokers . With our experience there is just no reason for paradox of choice adding extra generic AMQP 1.0 capabilities to Spring.
Comment From: artembilan
See more info here: https://github.com/spring-projects/spring-amqp/issues/2217
Comment From: artembilan
So, I have just pushed spring-rabbitmq-client
module with few important classes:
1. AmqpConnectionFactoryBean
to expose Connection
object configuration in Spring manner. Requires Environment
from RabbitMQ AMQP Client.
2. RabbitAmqpAdmin implements AmqpAdmin
for API to handle topology in Spring manner. The most important part that it can deal with Declarable
bean. Just exactly similar to the RabbitAdmin
, but over AMQP 1.0 protocol with RabbitMQ.
3. RabbitAmqpTemplate
with async send
and receive
operation implementations (for now).
See more info in the linked sub-issues.
Comment From: artembilan
OK. Added listener side API together with tests.
There is a RabbitAmqpListenerTests
which demonstrates how this new module can be used to consume messages from RabbitMQ AMQP 1.0 via @RabbitListener
.
I think that's enough for now and next stop will be docs which would close this issue. The rest of improvements after feedback.
Comment From: eddumelendez
Hi @artembilan, is possible to add RabbitAmqpTemplate#execute
method similar to RabbitTemplate#execute
? The idea is to perform something similar to RabbitHealthIndicator
Comment From: artembilan
Hi @eddumelendez !
Thank you for feedback!
Well, there is no channel
abstraction in AMQP 1.0, therefore no need to worry about context and Connection
object can be used concurrently.
However I see your (and already felt it myself) pain because there is no low-level driver (ProtonJ2) exposed from RabbitMQ AMQP Java Client. But we can ask @acogoluegnes to provide at least broker version
property on the connection , or management …
Comment From: eddumelendez
Thanks! looking forward to it.
Also, would like to share that I started prototyping a spring boot auto-configuration and noticed a few things
RabbitAmqpTemplate
doesn't allow to configureRetryTemplate
. Meanwhile,RabbitAmqpListenerContainerFactory
allow it.RabbitAmqpTemplate#setKey
could be renamed tosetRoutingKey
AmqpConnectionFactoryBean#createInstance
creates aConnection
using aConnectionBuilder#build
which performs an actual call to RabbitMQ instance and make the testing part a little bit complex.
Comment From: acogoluegnes
It is possible to register a StateListener
on the connection to track its state. That should be enough for a health indicator.
Comment From: artembilan
Hi @acogoluegnes !
Yes, the StateListener
is good to catch such events internally in the application logic.
The health indicator is a Spring Boot high-level API to be called externally: https://docs.spring.io/spring-boot/reference/actuator/endpoints.html#actuator.endpoints.health.
The mentioned RabbitHealthIndicator
for AMQP 0.9.1 does this:
@Override
protected void doHealthCheck(Health.Builder builder) throws Exception {
builder.up().withDetail("version", getVersion());
}
private String getVersion() {
return this.rabbitTemplate
.execute((channel) -> channel.getConnection().getServerProperties().get("version").toString());
}
Something similar we can see for JMS:
@Override
protected void doHealthCheck(Health.Builder builder) throws Exception {
try (Connection connection = this.connectionFactory.createConnection()) {
new MonitoredConnection(connection).start();
builder.up().withDetail("provider", connection.getMetaData().getJMSProviderName());
}
}
The MongoDB one is:
@Override
protected void doHealthCheck(Health.Builder builder) throws Exception {
Document result = this.mongoTemplate.executeCommand("{ hello: 1 }");
builder.up().withDetail("maxWireVersion", result.getInteger("maxWireVersion"));
}
So, feels like for AMQP 1.0 we would expect the broker version
info as well.
For now, @eddumelendez , the regular RabbitTemplate
should be enough.
Even if it is AMQP 0.9.1, it still connects to the same broker over the same port.
So, from the application perspective, it does not matter how we check RabbitMQ broker connectivity.
Only downside that there is going to be extra connection to the broker and that one is for 0.9.1 protocol.
Comment From: artembilan
@eddumelendez ,
RabbitAmqpTemplate
doesn't allow to configureRetryTemplate
.
That's correct, because all the operations in the RabbitAmqpTemplate
are CompletableFuture
-based. Therefore it is not possible to retry them with standard RetryTemplate
.
There is no async retry in Spring Retry yet: https://github.com/spring-projects/spring-retry/pull/176.
Perhaps Resilience4j can help some how, but that's different story: https://stackoverflow.com/questions/62084143/resilience4j-returning-a-completablefuture-around-tried-method
RabbitAmqpTemplate#setKey
could be renamed tosetRoutingKey
Will fix that today.
using a
ConnectionBuilder#build
which performs an actual call to RabbitMQ
Yes, I had those doubts as well. It is really not very good to have a low-level connection just during initialization phase.
Wanted to stay away from ConnectionFactory
abstraction.
I would like to know more about your tests and what really complexity are you facing. Look into my tests: https://github.com/spring-projects/spring-amqp/blob/main/spring-rabbitmq-client/src/test/java/org/springframework/amqp/rabbitmq/client/RabbitAmqpTestBase.java I just use Testcontainers for the latest RabbitMQ image and configure these two beans:
@Bean
Environment environment() {
return new AmqpEnvironmentBuilder()
.connectionSettings()
.port(amqpPort())
.environmentBuilder()
.build();
}
@Bean
AmqpConnectionFactoryBean connection(Environment environment) {
return new AmqpConnectionFactoryBean(environment);
}
Yes, it might connect immediately, but that is light operation as a handshake between client and broker. Or do you mean it cause a problem when no really broker running? And perhaps connection goes to its recovery cycle causing the whole application initialization phase to be blocked. Would you mind to elaborate?
Comment From: eddumelendez
Or do you mean it cause a problem when no really broker running?
Yes, auto-configuration tests don't use Testcontainers because it checks different configurations as part of the unit tests. See RabbitAutoConfigurationTests
I tried mocking the Connection
, but then failed with PublisherBuilder
is null. I didn't try that yesterday and since I was already providing some notes here I decided to share it here as well too.
Comment From: artembilan
OK. So, I'll bite a bullet and will introduce an AmqpConnectionFactory
abstraction to initiate connection in lazy manner.
Probably something like RoutingAmqpConnectionFactory
could be implemented later on to allow to chose different connections at runtime.
Comment From: acogoluegnes
@artembilan The AMQP 0.9.1 health check is the only one returning the product version: JMS returns the provider name and MongoDB returns the wire protocol version (not the same as MongoDB version).
I think something like should do the trick (assuming there is a StateListener
that tracks the connection state):
builder.up().withDetail("state", state.name());
WDYT?
Comment From: artembilan
Well, @acogoluegnes , that still would work for me. I'm not sure what are criteria in Spring Boot for those health details, but I see that it is really not consistent. For example, this one for Cassandra: https://github.com/spring-projects/spring-boot/blob/main/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/cassandra/CassandraDriverHealthIndicator.java.
I think this might easy go for discussion to Spring Boot project since there is really nothing I can do from Spring AMQP perspective for the current expose of the RabbitMQ library. I can join discussion if necessary, but that decision is out of my scope and responsibility.
Comment From: artembilan
Hi @eddumelendez !
I know this is an old story, but I wonder where is your attempt to contribute this new Spring AMQP feature to Spring Boot? Thanks