Getting started
Install
Not published yet. This library has its own version line starting at
0.1.0and has not had a release. Until it does, build it from source withmvn install. The coordinates below are what a release will use.
<repositories>
<repository>
<id>acemq</id>
<url>https://acemq-company.github.io/maven/</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>org.acemq</groupId>
<artifactId>acemq-java-rabbitmq-admin</artifactId>
<version>0.2.0</version>
</dependency>
</dependencies>Gradle:
repositories {
mavenCentral()
maven { url = uri("https://acemq-company.github.io/maven/") }
}
dependencies {
implementation("org.acemq:acemq-java-rabbitmq-admin:0.1.0")
}Java 11 or later. One artifact, and the HTTP client is the JDK's own
java.net.http — there is no Apache HttpClient or OkHttp
underneath it, so this does not join a version argument your application
is already having.
Its version line is separate from AceMQ for Java's. This tracks RabbitMQ's management API; that tracks AceMQ's messaging API, and the two move for different reasons.
A broker to talk to
The management API is a plugin, and on the management
images it is already on:
docker run -d --name rabbit \
-p 5672:5672 -p 15672:15672 -p 15692:15692 \
rabbitmq:4-managementPort 15672 is the management API. Port 15692 is the Prometheus endpoint, which is a different plugin and is not enabled by default:
docker exec rabbit rabbitmq-plugins enable rabbitmq_prometheusYou only need that second one for metrics and alerts.
Connect
import org.acemq.rabbitmq.admin.RabbitAdmin;
import org.acemq.rabbitmq.admin.QueueInfo;
try (RabbitAdmin admin = RabbitAdmin.connect("http://localhost:15672", "guest", "guest")) {
System.out.println(admin.version()); // "4.1.0"
}RabbitAdmin is AutoCloseable. It is cheap
to create and safe to keep for the lifetime of an application; it holds
one HttpClient.
The credentials are the broker's own users, not your
application's. The user needs the monitoring tag to read
and administrator to write. A user that can publish and
consume perfectly well may still get a 401 here, and that is not a
misconfiguration — it is the management API being a separate permission
surface.
Read a queue
Optional<QueueInfo> maybe = admin.queue("orders.new");
QueueInfo queue = maybe.orElseThrow(() -> new IllegalStateException("not declared"));
System.out.println(queue.type()); // "classic" or "quorum"
System.out.println(queue.durable()); // true
System.out.println(queue.arguments()); // {x-message-ttl=60000, ...}
System.out.println(queue.messagesReady()); // 42
System.out.println(queue.consumers()); // 3A queue that does not exist is Optional.empty(), not an
exception. Bad credentials are an exception — reporting them as
"no queue" would send somebody looking in entirely the wrong place.
messagesReady() rather than messages() is
almost always the number you want. The total includes deliveries already
handed to a consumer, so it stays high while a consumer works through a
batch and tells you nothing about whether the queue is draining.
Check your permissions at startup
CurrentUser me = admin.whoami();
System.out.println(me.name() + " " + me.tags()); // guest [administrator]
if (!me.canAdminister()) {
throw new IllegalStateException(me.name() + " cannot change anything through the"
+ " management API: it needs the administrator tag");
}Worth doing once, at startup. Every permission problem otherwise surfaces later as a 401 or 403 on some unrelated-looking call, and "this user has no administrator tag" is a much better thing to report than "could not create vhost" an hour into a provisioning run.
Upgrade readiness
admin.deprecatedFeaturesInUse().forEach(f ->
System.out.println(f.name() + " " + f.deprecationPhase()));
admin.featureFlags().stream()
.filter(FeatureFlagInfo::isRequired)
.filter(f -> !f.isEnabled())
.forEach(f -> System.out.println("blocks the next upgrade: " + f.name()));Both lists should be empty before a major upgrade. A required feature flag left disabled will stop the upgrade; a deprecated feature in use will stop working during it. RabbitMQ 4 already denies transient non-exclusive queues, which means a client declaring one has its connection closed with an internal error rather than a warning.
Choosing a vhost
Every call is scoped to one vhost, / by default:
RabbitAdmin billing = admin.forVhost("billing");forVhost returns a new view over the same connection; it
does not mutate the original. The default vhost is literally named
/, which the library encodes for you — see queues for why that detail has teeth.
Next
- Queues — the questions AMQP cannot answer
- Provisioning — vhosts, users, permissions, policies
- Tutorials — step by step, start to finish