markup/rabbitmq-management-api
A Laravel/PHP client for the RabbitMQ Management HTTP API. Inspect queues, exchanges, bindings, connections and node statistics, publish messages, and manage vhosts and policies through a clean, fluent wrapper. Ideal for dashboards and admin panels.
Enable the management plugin and confirm the API answers before writing any PHP:
rabbitmq-plugins enable rabbitmq_management
curl -u guest:guest http://localhost:15672/api/overview | jq .rabbitmq_version
Create a dedicated user rather than reusing guest. For read-only monitoring use the monitoring tag; only provisioning/deletion code needs administrator/management:
rabbitmqctl add_user app_monitor 's3cret'
rabbitmqctl set_user_tags app_monitor monitoring
rabbitmqctl set_permissions -p / app_monitor ".*" ".*" ".*"
Install the package and expect friction: the last release was 2019, so check composer require markup/rabbitmq-management-api against your PHP version. On PHP 8.2+ you will likely need a fork or --ignore-platform-reqs because the composer.json constraint was written for 7.x.
The client is a thin HTTP wrapper — constructor takes host/port/credentials (and often a vhost), and methods map one-to-one onto /api/* endpoints (overview, nodes, queues, exchanges, bindings, connections, channels, consumers). Read the src/ directory once before use; there are only a handful of classes, and the exact method names/argument order are not documented beyond the README. Bind it as a singleton in a service provider so you control timeouts and credentials in one place:
// config/rabbitmq.php
return [
'host' => env('RABBITMQ_MGMT_HOST', 'rabbitmq'),
'port' => env('RABBITMQ_MGMT_PORT', 15672),
'user' => env('RABBITMQ_MGMT_USER', 'app_monitor'),
'password' => env('RABBITMQ_MGMT_PASSWORD'),
'vhost' => env('RABBITMQ_VHOST', '/'),
'secure' => env('RABBITMQ_MGMT_TLS', false),
];
// AppServiceProvider::register()
$this->app->singleton(\Markup\RabbitMqManagement\Client::class, fn () => new \Markup\RabbitMqManagement\Client(
config('rabbitmq.host'),
config('rabbitmq.port'),
config('rabbitmq.user'),
config('rabbitmq.password'),
config('rabbitmq.vhost'),
));
First real use case: an Artisan command that prints cluster state, so you have a smoke test and an ops tool at the same time.
// php artisan rabbitmq:status
$overview = $client->overview();
$this->table(['Cluster', 'Version', 'Queues', 'Messages'], [[
$overview['cluster_name'],
$overview['rabbitmq_version'],
$overview['object_totals']['queues'],
$overview['queue_totals']['messages'],
]]);
Two clients, two credentials. Keep the monitoring user for dashboards/alerts and a separate administrator client for provisioning code. That way a bug in a dashboard endpoint can never purge a queue, and revocation is per-concern.
Wrap it in your own interface. This package is a 2019 micro-wrapper with no PSR-18 support and no Laravel auto-discovery. Define App\RabbitMq\AdminClient with the eight or so methods you actually call, implement it with this package, and inject the interface. Migration cost later is one file instead of a grep across the codebase.
interface RabbitAdmin {
public function overview(): array;
public function queues(string $vhost, array $query = []): array;
public function queue(string $vhost, string $name): array;
public function purge(string $vhost, string $name): void;
public function publish(string $vhost, string $exchange, array $payload): void;
}
Queue-depth alerting on a schedule. This is the highest-value daily use. Run every minute (or every five), compare messages_ready to a per-queue threshold from config, and use Cache::lock to avoid notification storms.
foreach (config('rabbitmq.alerts') as $name => $threshold) {
$q = $client->queues(config('rabbitmq.vhost'), ['name' => $name, 'use_regex' => 'false', 'page_size' => 1]);
$ready = $q[0]['messages_ready'] ?? 0;
if ($ready > $threshold) {
Notification::route('slack', config('slack.ops'))->notify(new QueueBacklog($name, $ready, $threshold));
}
}
Track messages_unacknowledged separately — a queue with low ready-but-high unacked counts means consumers are hung, not that work has drained.
Health endpoint for load balancers and uptime checks. Distinguish "management API unreachable" (network/TLS) from "401" (bad credentials) from "503" (broker down). Cache the result for 15–30 seconds and return 200/503; don't call /api/overview from a hot request path.
Test-suite provisioning and teardown. Instead of shelling out to rabbitmqctl, declare test vhosts/queues/exchanges/policies through the API in setUpBeforeClass() and delete them in teardown. deleteQueue supports if-empty/if-unused query params when supported by the method signature — otherwise delete explicitly after purging.
Publish directly to an exchange for integration tests via the management publish endpoint (payload, payload_encoding = string, routing_key, properties). This exercises the consumer path without opening an AMQP connection, which keeps test setup synchronous and avoids socket leaks between test runs.
Pagination for inventory jobs. /api/queues is paginated at 100 items by default. For a "list everything" report, loop with page until a short page comes back, and pass columns=name,messages,messages_ready,consumers,state to cut payload size dramatically on large clusters.
Prefer scoped endpoints. queues($vhost) and queue($vhost, $name) are far cheaper than the global /api/queues, which has to aggregate across every vhost and is a known pain point on clusters with thousands of queues.
/, which must be %2F in the URL. If the package doesn't encode it for you, pass %2F explicitly or you'll get a confusing 404 for "vhost /".queues() never returns "all queues" — it returns one page. Anything that assumes a full list will mysteriously miss queues once you pass 100 objects.messages is a sum of messages_ready + messages_unacknowledged computed by the broker, refreshed every ~5 seconds. Idle queues can show stale or zero values until traffic resumes. Don't build billing or exact accounting on these numbers./api/overview is not free on large clusters — it triggers aggregation across nodes. Cache it, and never let a health check hammer it at high frequency.null depending on the method. Wrap every call and normalize into your own exception types; specifically map 401 → credentials problem, 404 → missing vhost/queue, 5xx → broker degraded.GuzzleHttp\Client, inject one with timeout => 2, connect_timeout => 1, and a single retry on connection errors. The default can hang well past a web request budget when a node is partitioned.verify => '/path/ca.pem' (or false only in local dev) through the injected Guzzle client. There is no config knob for this in the package.# or @ in the password, that's why — use a basic-auth header or urlencode.deleteQueue drops messages. There's no undo. Gate destructive methods behind a separate admin-only credential and never expose them via a dashboard route.packages/, and keep all usage behind RabbitAdmin. Because the surface area you actually need is small — roughly eight endpoints — replacing it with 100 lines of Laravel's Http facade is a viable fallback if a PHP upgrade breaks it. Don't let it spread beyond the adapter.RabbitAdmin; only a nightly or CI integration job should touch a live management API.How can I help you explore Laravel packages today?