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

Mq2Php Bundle Laravel Package

happyr/mq2php-bundle

Symfony bundle for bridging message queues to PHP consumers, simplifying queued message consumption and processing through configurable services and console commands.

View on GitHub
Deep Wiki
Context7

Getting Started

Know what you're installing first. happyr/mq2php-bundle is a Symfony bundle, not a Laravel package. There is no ServiceProvider, no facade, no extra.laravel auto-discovery, and no config file that lands in config/. What it actually ships is a thin Symfony wrapper around the standalone happyr/mq2php worker library: a long-polling SQS consumer that reads a JSON message, resolves a service from the DI container, and calls a method on it. Treat it as a reference implementation for "SQS queue → PHP handler" rather than something you install into a Laravel app.

Where to look first (in this order):

  1. README.md — the message envelope format and the YAML config keys are the only things that matter.
  2. DependencyInjection/Configuration.php — the authoritative list of config keys (queue_url, AWS credentials/region, and the handler-service map). If the README and this file disagree, this file wins.
  3. Command/ — find the runnable worker command (mq2php:…); that's the entry point you'll be reimplementing.
  4. composer.json — check require for PHP and aws/aws-sdk-php constraints before trying to install. With a 2018-01-29 last release this is almost certainly pinned to PHP 7.x and AWS SDK v3-era APIs.

If you are in Symfony, the minimal path is: composer require happyr/mq2php-bundle, register the bundle in AppKernel/bundles.php, add a happyr_mq2php: block to config.yml with your queue URL, region, and a map of message service names to container service IDs, then run the worker command under Supervisor.

If you are in Laravel — which is the actual scenario — do not install this bundle. You will spend more time fighting Symfony's container than writing the worker. The equivalent is roughly 40 lines:

// app/Console/Commands/ConsumeSqs.php
$sqs = new SqsClient(['region' => config('services.sqs.region'), 'version' => 'latest']);

while ($this->running) {
    $result = $sqs->receiveMessage([
        'QueueUrl'            => config('services.sqs.url'),
        'MaxNumberOfMessages' => 10,
        'WaitTimeSeconds'     => 20,   // long poll
    ]);

    foreach ($result->get('Messages') ?? [] as $msg) {
        $envelope = json_decode($msg['Body'], true, 512, JSON_THROW_ON_ERROR);
        app($this->handlers[$envelope['service']])->handle($envelope['arguments']);

        $sqs->deleteMessage([
            'QueueUrl'      => config('services.sqs.url'),
            'ReceiptHandle' => $msg['ReceiptHandle'],
        ]);
    }
}

First real use case: you have an existing SQS queue that another team or another service already writes to, and you need a PHP process to drain it. That's the one job this bundle describes well — copy the pattern, don't copy the dependency.

Implementation Patterns

The envelope pattern is the actual value here. mq2php messages are self-describing: a JSON body naming a logical handler plus its payload, e.g. {"service": "user_created", "method": "handle", "arguments": {...}}. Producers only need to know a string alias, not a class name, not a queue consumer's internals. Keep that discipline even in your Laravel rewrite — it's what lets you add handlers without redeploying producers.

Handler-as-adapter. Each mapped "service" should be a one-method class whose only job is to translate the envelope into a Laravel job or action:

class UserCreatedHandler
{
    public function handle(array $arguments): void
    {
        dispatch(new SyncUserProfile($arguments['user_id']));
    }
}

Resolve handlers from a match statement or a config/mq2php.php map of alias => class. Don't let the consumer class grow conditionals.

Producer side — pick one, not both:

  • Raw SQS if other languages consume the same queue: $sqs->sendMessage(['QueueUrl' => …, 'MessageBody' => json_encode($envelope)]).
  • Laravel's SQS driver if it's PHP-only: Queue::connection('sqs')->pushRaw(json_encode($envelope), $queueName). This buys you free retries/backoff via queue:work, but note that Laravel's SQS driver has its own envelope assumptions when using push() — pushRaw() keeps your format intact.

Supervisor + graceful restart. The worker is a daemon. Run one Supervisor program per queue with numprocs tuned to your throughput, and give it a stop signal handler (pcntl_signal + a $this->running flag, or Laravel's queue:restart cache flag) so deploys don't drop in-flight messages. Set stopwaitsecs above your longest handler runtime.

Two-tier dispatch. For anything non-trivial, do not process inline in the consumer loop. Consume → dispatch(new Job(...)) → let PHP-FPM-less queue workers do the real work. This decouples SQS visibility timing from your business logic runtime, which is the single biggest operational win.

Testing. Inject the SqsClient behind an interface and swap in a fake in tests; assert that a given envelope routes to the right handler class. Handler tests are plain unit tests — no queue involved.

Gotchas and Tips

It is abandoned. Last release January 2018, 1 star, 0 dependents. There is no maintainer to answer issues, and it predates Symfony 4's flex-era bundle conventions and modern PSR-11 container signatures. Do not put this in a production composer.json — fork the two or three classes you need.

PHP and AWS SDK version drift will block the install. The composer.json constraints almost certainly exclude PHP 8 and require an AWS SDK major version you aren't using. If composer require doesn't resolve, stop there — that's the answer, not a puzzle.

Container incompatibility is the real trap. The bundle resolves handlers through Symfony's ContainerInterface. Laravel's container is PSR-11-compatible but not Symfony-DI-compatible; the service-locator semantics, lazy services, and bundle config compilation have no Laravel analogue. Any "bridge" you write is a bridge to nothing.

Visibility timeout is the #1 production bug. SQS makes a received message invisible for the queue's visibility timeout. If that's shorter than your handler runtime, the message is redelivered and processed twice. Set visibility timeout to at least 2–3× your p99 handler time, and call ChangeMessageVisibility for known-long jobs rather than guessing.

At-least-once delivery is a guarantee, not a nuisance. Handlers must be idempotent. Dedupe on a business key (user_id + event type) or a producer-supplied message_id. Never rely on SQS FIFO ordering alone for correctness.

Delete only on success. The classic bug: deleteMessage in a finally block. A throwing handler then silently loses the message. Delete after the handler returns; on exception, log with the MessageId, let visibility expire, and rely on a redrive policy → DLQ.

No DLQ, retry, or metrics config ships with the bundle. Configure the redrive policy on the queue itself (AWS console / IaC), and add your own logging: message ID, envelope service name, duration, outcome. There are zero extension points for observability here — you're adding them at the Laravel layer.

Extension points, such as they are: override the worker service definition in DI to swap in your own loop, or decorate the handler resolver. Beyond that, the classes are small enough to fork. If you're forking anyway, you're already writing the Laravel version — just do that instead.

Debugging checklist when messages vanish: (1) is the message in the DLQ or still in-flight? (2) ApproximateReceiveCount climbing = handler is throwing or timing out; (3) message never arrives = IAM permissions on ReceiveMessage/DeleteMessage or wrong QueueUrl (it's the full URL, not the name); (4) consumer idle but MessagesAvailable > 0 = your long-poll thread died and Supervisor didn't restart it.

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.
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource