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

Amqp Laravel Package

psyllium/amqp

psyllium/amqp brings AMQP/RabbitMQ messaging to Laravel and PHP applications, offering a simple API for publishing and consuming messages, declaring exchanges and queues, and integrating asynchronous workflows into your app.

View on GitHub
Deep Wiki
Context7

Getting Started

Confirm the hard requirements before anything else. This package is not a pure-PHP AMQP client — it wraps psyllium/psyllium, which sits over the native ext-amqp extension. If the extension is missing, nothing installs or runs.

php -m | grep -i amqp        # must print "amqp"
pecl install amqp            # requires librabbitmq-dev / libssl headers on the host
composer require psyllium/amqp

Watch the install path. The repository is Bitbucket-hosted (bitbucket.org:ebrandpl/amqp). If it is not on Packagist, you must add it as a VCS repository in composer.json and make sure CI and every deploy target can authenticate to Bitbucket — otherwise your builds break the moment a new engineer or pipeline clones the project:

"repositories": [
  { "type": "vcs", "url": "[email protected]:ebrandpl/amqp.git" }
]

Understand what you actually installed. Despite the Laravel-flavored description, the shipped integration is a Symfony bundle (Psyllium\Amqp\Symfony\PsylliumAmqpBundle). It gives you a container-managed Psyllium\Connection/Psyllium\Producer; it does not register a Laravel Queue driver, an Event transport, or a Job payload format. Plan for that gap up front.

Registration (Symfony app inside your Laravel-adjacent stack):

// config/bundles.php
return [
    Psyllium\Amqp\Symfony\PsylliumAmqpBundle::class => ['all' => true],
];

Minimal config — the config tree is connection-centric:

# config/packages/psyllium_amqp.yaml
psyllium_amqp:
    connections:
        default:
            host: '%env(AMQP_HOST)%'
            port: 5672
            login: '%env(AMQP_USER)%'
            password: '%env(AMQP_PASS)%'
            vhost: '/'

First use case — publish a single message to an exchange:

use Psyllium\Producer;

final class WelcomeMailer
{
    public function __construct(private Producer $producer) {}

    public function queue(string $email): void
    {
        $this->producer->publish(
            json_encode(['email' => $email]),
            'welcome',        // routing key
            'notifications'   // exchange
        );
    }
}

Where to look first in the repo, in this order:

  1. src/DependencyInjection/Configuration.php — the only trustworthy source of which YAML keys exist and what they default to. Do not trust README snippets.
  2. src/Resources/config/services.xml — the service IDs, and whether services are public (injectable) or private (needs aliasing).
  3. src/DependencyInjection/*Extension.php — how connections and producers get built from config.
  4. The upstream psyllium/psyllium README — this bundle is largely a service-definition shim; the real Producer/Consumer API lives upstream.

Implementation Patterns

One connection per broker, many producers/consumers per connection. The extension builds one Psyllium\Connection per entry under connections, and your publisher/consumer services receive that connection as a constructor argument. Model your app the same way: register a single default connection and inject producers, rather than opening connections ad hoc inside request handlers.

Publisher wrapper — never call Psyllium\Producer from controllers/jobs directly. The whole risk profile of this package is "single maintainer, unknown upgrade path." Isolate it behind your own contract so you can swap to vladimir-yuldashev/laravel-queue-rabbitmq or php-amqplib later without touching call sites:

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

final class AmqpPublisher implements MessagePublisher
{
    public function __construct(private \Psyllium\Producer $producer) {}

    public function publish(string $routingKey, array $payload): void
    {
        $this->producer->publish(json_encode($payload), $routingKey, 'events');
    }
}

Bind the interface in your container and inject the interface everywhere else. This is the single most important pattern for this package.

Configure topology in config, not in PHP. Exchanges, queues, and bindings should be declared in YAML/config so they match between producers and consumers and can be reasoned about in one place. Keep the exchange name and routing-key conventions centralized (enum class or config constant); ad-hoc string literals are how routing-key mismatches get shipped.

Consumer/worker pattern. Consuming is the harder half and the least visible in the repo. Run consumers as a dedicated long-lived process (a console command or a php artisan-style worker), not inside web requests. Validate the following against a real broker before trusting them in production, because the bundle does not make them explicit:

  • prefetch / basic_qos settings and where they come from
  • behavior when the broker connection drops mid-consume
  • acknowledgement strategy and what happens on an uncaught exception
  • graceful shutdown on SIGTERM

Integration tip — environment separation. Because config is YAML-first, drive every value from env vars and keep per-environment vhosts/exchange names distinct. That lets you point the same code at a local RabbitMQ container and a staged cluster without code changes.

Local dev workflow. Put a RabbitMQ container with the management plugin in docker-compose.yml. Use the management UI to inspect exchanges, queues, bindings, and message rates — this is your primary debugging surface, because the package gives you almost no observability.

Pilot the riskiest integration point first. Do a thin publish test, then a consume test, before wiring it into any real workflow. Confirm the serialization format matches what your consumers expect — this package does not standardize payload shape, so it is on you.

Gotchas and Tips

  • ext-amqp is non-negotiable. No pure-PHP fallback. This alone disqualifies it on shared hosting, many serverless runtimes, and Alpine images without the build toolchain. Bake the extension into your Docker base image.
  • Bitbucket availability is a dependency. If the repo is private or later made private, a fresh composer install in CI fails. Mirror the package into your own vendor namespace (a fork) and pin a reviewed commit. Assume you are the maintainer.
  • It is not a Laravel queue driver. Do not expect dispatch() on jobs, Queue::push(), failed_jobs integration, Horizon dashboards, or Laravel's job payload format. Any attempt to bridge it into Laravel's queue contracts is bespoke glue you write and own.
  • Connection lifecycle in long-lived workers. This is the classic AMQP footgun and the package does not visibly solve it: channels die on broker restarts and must be re-established; consumers that swallow the exception silently stop consuming. Add heartbeats, reconnect-with-backoff, and a health check that asserts the consumer is actually receiving messages.
  • Poison messages and DLQ. There is no evidence of built-in dead-lettering or retry routing. Design explicit DLX/DLQ topology in your RabbitMQ config and prove behavior with a message your consumer always throws on — otherwise a single bad message can wedge a queue.
  • Config key names betray the Symfony origin. Note login/password (not user/password), vhost with a leading /. Copy keys from Configuration.php, not from blog snippets; a typo'd key is silently ignored by Symfony's config tree rather than erroring.
  • Service visibility. If a producer/consumer service is private in services.xml, injection by class name fails unless the bundle declares aliases. When you hit "service not found," check the XML before assuming the extension is broken.
  • Serialization is on you. publish() takes a string/body; whether that is JSON, MessagePack, or a Symfony-serialized envelope is your decision. Pick one format, document it, and write a contract test — this is where a future transport swap most easily breaks consumers.
  • Debugging playbook. (1) RabbitMQ management UI for queue depth, deliver/ack rates, unacked messages; (2) rabbitmqctl list_queues name messages consumers for stuck queues; (3) broker logs for connection churn; (4) only then the package code. If messages vanish, check the exchange type and that a binding actually exists for your routing key — an exchange with no matching binding silently drops.
  • Testing. Integration-test against a disposable RabbitMQ (Testcontainers or a compose service) rather than mocking the producer interface only — mocking hides the routing-key/binding mistakes that the broker would reject.
  • Extension points are thin. The realistic extension point is not the bundle but the psyllium/psyllium API underneath it. If you need retry, DLQ, metrics, or correlation-ID propagation, you will either add it in your own wrapper or fork the package. Budget for the fork.
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.
diephp/sequences
users-au/socialite-provider
twidpay/twid-logger
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator
itstructure/laravel-multilingual-tools
pdustdar/elasticsearch
markupai/php-sdk
rlacerda83/lumem-microservice-shipment
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle