Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Xz Rabbitmq Bundle Laravel Package

panghaibo/xz-rabbitmq-bundle

A PHP bundle for RabbitMQ integration, helping you configure connections, publish messages, and consume queues for asynchronous workflows in your applications.

View on GitHub
Deep Wiki
Context7

Getting Started

Confirm the framework mismatch first. xz-rabbitmq-bundle is a Symfony bundle, not a Laravel package. The Bundle suffix, the rabbitXzBundle repo name, and the likely DependencyInjection/Extension + Resources/config/services.yaml layout all point to Symfony DI conventions. In a pure Laravel app, you cannot composer require it and expect a working service provider — you'll be fighting autoloading and pulling Symfony framework dependencies. Two realistic entry points:

  • Symfony app: register it in config/bundles.php and let the extension load services as intended.
  • Laravel app: treat it as reference source only, copy the relevant connection/consumer/monitoring classes, and adapt them behind your own service provider. Do not attempt a naive composer require.

Where to look first (in this order):

  1. composer.json — what does it actually autoload (psr-4 roots), what PHP version, and which AMQP client does it depend on (php-amqplib/php-amqplib, ext-amqp, or something raw)?
  2. The DependencyInjection/ classes — this is where config keys are defined and services are wired. Read this before the config file so you understand defaults and required values.
  3. The connection/channel factory — how are connections created, are they shared, is there heartbeat/reconnect logic, or is it delegated?
  4. The publisher class — payload serialization (JSON vs PHP serialize), properties set (delivery mode, correlation id, expiration).
  5. The consumer/dispatcher class — prefetch/QoS, ack/nack semantics, error handling, dead-letter support.
  6. The monitoring code — this is the reason the package exists ("二次开发 加入监控程序"). Find: what metrics, what transport (log/statsd/HTTP/AMQP), is emission synchronous, and what happens when the monitoring backend is unreachable.

First use case (safe, non-critical): a low-volume, idempotent worker — audit fan-out, notification emails, cache warmup. Publish a JSON message from a controller/service, consume it in a worker process, watch a monitoring record appear. This proves the wiring end-to-end without putting revenue paths at risk.

Minimum viable config to get a message round-tripping:

# symfony config/packages/xz_rabbitmq.yaml (shape is illustrative — verify keys in the DI extension)
xz_rabbitmq:
    connections:
        default:
            host: '%env(RABBITMQ_HOST)%'
            port: '%env(int:RABBITMQ_PORT)%'
            user: '%env(RABBITMQ_USER)%'
            password: '%env(RABBITMQ_PASSWORD)%'
            vhost: '%env(RABBITMQ_VHOST)%'
    exchanges:
        app_events:
            type: topic
    queues:
        audit_worker:
            exchange: app_events
            routing_key: 'audit.#'
    monitoring:
        enabled: true
        # whatever transport the bundle exposes — confirm in DI before assuming

Do not guess keys — open the Extension class and confirm every one. Undocumented config is the number-one source of "it silently does nothing" here.

Implementation Patterns

Adapter boundary (do this before anything else). Define your own interfaces in application code and implement them with this bundle. This is the single highest-value pattern for a package of this maturity — it makes the vendor swappable and contains the abandonment blast radius.

namespace App\Messaging;

interface Publisher
{
    public function publish(string $routingKey, array $payload): void;
}

interface Consumer
{
    public function consume(string $queue, callable $handler): void;
}

Your XzRabbitPublisher implements Publisher and delegates to the bundle; nothing else in the app knows the bundle exists. When you fork or replace it, you rewrite one class.

Publishing pattern — JSON payloads, explicit properties. Assume the bundle serializes payloads; do not rely on it to set durable delivery. Check the publish path and set:

  • delivery_mode = 2 (persistent) if the queue is durable — otherwise a broker restart loses messages
  • content_type = application/json so consumers (including future non-PHP ones) can parse the message
  • correlation_id propagated from the request/job context — essential for tracing a message through the monitoring records
  • expiration per message rather than per queue when you have mixed lifetimes on one queue

Consumer pattern — bounded handler, explicit ack semantics.

public function consume(string $queue, callable $handler): void
{
    $this->consumer->run($queue, function ($message) use ($handler) {
        try {
            $handler(json_decode($message->getBody(), true, 512, JSON_THROW_ON_ERROR));
            $message->ack();
        } catch (\Throwable $e) {
            $this->log->error('consumer.failed', ['queue' => $queue, 'error' => $e->getMessage()]);
            $message->nack(); // or reject + requeue depending on retry policy
        }
    });
}

Never let an exception escape the consumer's ack/nack boundary — that's how you get unacked message accumulation and connection stalls.

Monitoring integration pattern. Wrap every metric emission in a fail-open boundary:

private function emit(string $metric, array $tags): void
{
    try {
        $this->monitoring->emit($metric, $tags);
    } catch (\Throwable $e) {
        // log at debug, drop the metric — never block the consume loop
    }
}

If the bundle's monitoring is on the critical path by design (synchronous flush, blocking HTTP), that's an audit finding — either wrap it as above or disable the built-in monitoring and emit your own metrics around the consumer loop.

Two-surface strategy: native queue driver + this bundle's monitoring only. If you are on Laravel with vladimir-yuldashev/laravel-queue-rabbitmq or illuminate/queue already, the durable pattern is:

  • Dispatch through the native driver (tested, maintained, integrates with dispatch(), retries, failed_jobs)
  • Monitoring evaluated against this bundle's approach — or, better, replicate its metric names against rabbitmq_exporter + Grafana

Do not run two parallel RabbitMQ connection managers in one worker process unless you have explicitly sized max_connections on the broker.

Fork-and-pin workflow. Given zero tags, single maintainer, and no CI:

# Fork into your VCS, then pin by commit SHA — not by version range
composer require your-org/xz-rabbitmq-bundle:dev-main#abc1234

Add a smoke test suite (connect → publish → consume → ack → nack) around the fork before deploying to anything beyond staging. This is your safety net because upstream has none.

Configuration via env, never checked in. Credentials and connection strings are the highest-risk items in a broker wrapper. Keep RABBITMQ_* in .env for local dev and in your secret manager for deploy. Check whether the monitoring component opens its own connection or HTTP endpoint — if so, it duplicates secrets into a second config surface, and you'll want to unify them.

Gotchas and Tips

Framework identity is the biggest trap. "Bundle" means Symfony. Before writing any integration code, verify whether the package is:

  • a Symfony bundle (most likely — Bundle suffix),
  • framework-agnostic PHP that happens to call itself a bundle, or
  • a mislabeled Laravel package.

The answer determines whether Laravel integration is "register a service provider" or "rewrite the DI wiring," which is a day vs. a week.

No releases, no tags — pin to a SHA. composer require panghaibo/xz-rabbitmq-bundle will likely resolve against a moving default branch. That's a supply-chain risk on a message path carrying credentials and payloads. Pin the fork to a specific commit and treat every upgrade as a code review, not a composer update.

Undocumented config is the base case. Expect to read the DependencyInjection/Configuration.php (or equivalent) to learn what keys are required vs. optional and what defaults apply. Common traps: default exchange type (direct vs topic), whether queues are declared passively or actively, whether auto_delete is on for queues you want durable. Nothing in the readme will tell you.

Monitoring failure semantics is the question that decides adoption. Answer, from source: if the monitoring backend is unreachable, does the consumer (a) log and continue, (b) block until timeout, or (c) crash the worker? On the consume loop, (b) is unacceptable — it caps per-consumer throughput and delays ack. Demand fail-open; if it isn't, wrap it or disable it.

Heartbeats and reconnect are likely your responsibility. Thin wrappers often delegate to the underlying AMQP client without adding reconnect-with-backoff. That means a dropped connection leaves the worker process "up" but consuming nothing — your liveness probe must catch this. Add an external check (queue depth growing + no consumer activity = dead worker) regardless of what the package claims.

Metric cardinality will bite you at scale. If the monitoring keys on queue name × routing key × consumer tag, a few hundred queues overwhelm Prometheus/statsd and you get slow scrapes and gaps. Confirm the label set before trusting dashboards — validate against rabbitmqctl list_queues name messages consumers ground truth.

Poison-message handling is not free. Nack-with-requeue without a retry ceiling creates an infinite redelivery loop that hammers your consumer. Set a dead-letter exchange and a retry ceiling at the queue level in config; do not rely on the consumer to be clever.

PHP version drift. Older packages in this ecosystem target PHP 7.x. Verify against your app's runtime (8.2+ is common now) before spending time on integration. If it fails to install on 8.2, that's your signal to stop.

Extension points — where to hook cleanly:

  • Transport: if the bundle uses a pluggable client interface, swap in your own instrumented client to add timing/error metrics without touching the bundle's consumer loop.
  • Handler layer: keep business logic entirely in your Consumer implementations, not in closures passed to the bundle. Easier to test, easier to migrate.
  • Monitoring emitter: if it exposes an emitter interface, implement a no-op or a buffered version for tests and for production fail-open.

Debugging checklist when a message disappears:

  1. Is the exchange declared with the expected type? Topic vs. direct mismatches silently drop.
  2. Is the routing key pattern correct? audit.# matches audit.user.login; audit.* does not.
  3. Is the queue bound? A declared queue with no binding accepts zero messages.
  4. Did publish use mandatory? Without it, unroutable messages vanish silently. Set it in a debug environment and add a return listener.
  5. Check rabbitmqctl list_bindings and rabbitmqctl list_queues — broker ground truth beats application logs every time.

Document your findings in the fork's readme. The one-maintainer, no-CI reality means the knowledge lives with whoever read the source. Write down: which client library, the monitoring transport, the failure semantics, the config keys, and the retry/DLX setup. That document is what stops the package from becoming single-threaded tribal knowledge on your team.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
skyraptor/chatter
edlugz/sasapay
abbasudo/artisan-route
mirvan/ippanel
ignibyte/aic-framework
glavweb/data-schema-bundle
glavweb/datagrid-bundle
tacticmedia/scim-server
uni-method/frame
neika-ai/sdk
adachsoft/php-code-style
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
adachsoft/api-version-bundle
cgv/localized-resource