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

Stomp Laravel Package

centraldesktop/stomp

A PHP client for the STOMP messaging protocol, enabling applications to connect to brokers, subscribe to destinations, send messages, and handle acknowledgements. Useful for integrating PHP apps with STOMP-compatible queues and messaging systems.

View on GitHub
Deep Wiki
Context7

Getting Started

The package is a non-Laravel, framework-agnostic STOMP client, so wiring it in is manual (there is no service provider or facade).

  1. Install it:

    composer require centraldesktop/stomp
    

    Note: the last tagged release is from February 2015. You may need to composer require centraldesktop/stomp:dev-master or check the autoloader works on your PHP version before investing further.

  2. Look first at the FuseSource\Stomp\Stomp class — it is the entire usable surface area. The companion FuseSource\Stomp\Frame class is what you get back from readFrame().

  3. A minimal round-trip to confirm the broker connection works:

    use FuseSource\Stomp\Stomp;
    
    $stomp = new Stomp('tcp://localhost:61613');
    $stomp->connect('admin', 'admin');
    
    $stomp->send('/queue/demo', 'hello world', ['persistent' => 'true']);
    
    $stomp->subscribe('/queue/demo');
    $frame = $stomp->readFrame();
    $stomp->ack($frame);
    
    $stomp->disconnect();
    

    The URI scheme (tcp://) and port (61613, the typical ActiveMQ STOMP port) are the parts that trip people up. If you are using the STOMP plugin on RabbitMQ, the port is 61613 as well, but the destination prefixes (/queue/…, /topic/…) and header semantics differ.

Your first real use case is almost always a producer: an OrderPlaced listener or a queued job that drops a message onto a destination that a non-PHP consumer (Java, Node, Go) is reading from.

Implementation Patterns

Bind a shared connection in a service provider. The Stomp object holds an open socket, so treat it as a singleton and be explicit about reconnect handling:

// AppServiceProvider::register()
$this->app->singleton(Stomp::class, function ($app) {
    $stomp = new Stomp(config('stomp.broker'));
    $stomp->connect(config('stomp.user'), config('stomp.pass'));
    return $stomp;
});

Do not share this singleton across parallel jobs when using pcntl-forking workers — each fork needs its own socket.

Producer pattern — send from an event listener or job. Keep sends small and set headers deliberately:

$stomp->send("/queue/{$queue}", json_encode($payload), [
    'persistent'          => 'true',
    'content-type'        => 'application/json',
    'correlation-id'      => (string) Str::uuid(),
    'reply-to'            => '/queue/replies',
]);

Consumer pattern — a long-running Artisan command. This is the idiomatic Laravel shape for a STOMP consumer; it gives you signals, logging, and restart hooks:

class ConsumeStomp extends Command
{
    protected $signature = 'stomp:consume {queue}';

    public function handle(Stomp $stomp): int
    {
        $stomp->subscribe($this->argument('queue'), ['ack' => 'client']);
        $stomp->setReadTimeout(5);

        while (true) {
            $frame = $stomp->readFrame();
            if ($frame === null) {
                continue; // timeout, loop back
            }

            try {
                $this->dispatch(new ProcessMessage($frame->body));
                $stomp->ack($frame);
            } catch (\Throwable $e) {
                Log::error('stomp consumer failed', ['err' => $e->getMessage()]);
                $stomp->nack($frame); // only valid on brokers that support NACK
            }
        }
        return self::SUCCESS;
    }
}

Selective consumption via headers. Instead of multiple queues, use a subscription header filter (ActiveMQ selector syntax):

$stomp->subscribe('/queue/orders', ['selector' => "type = 'refund'"]);

This is the cheapest way to fan out a single queue to multiple Laravel worker processes by responsibility.

Transactions for atomic multi-send. STOMP transactions are scoped to one connection and wrap sends/acks:

$tx = $stomp->begin();
$stomp->send('/queue/a', 'one', ['transaction' => $tx]);
$stomp->send('/queue/b', 'two', ['transaction' => $tx]);
$stomp->commit($tx); // or ->abort($tx)

Bridge to Laravel's queue system. A common pattern is to use Laravel's native queue:work for PHP-side jobs and reserve STOMP for cross-language traffic (Java consumers, ESB integrations). Do not try to make STOMP the backing store for Laravel's queue — writing a full Queue driver against it is more work than the package warrants.

Gotchas and Tips

  • Package age is the dominant risk. The codebase predates PHP 8. Expect deprecation warnings, and test the connect() path on PHP 8.2+ before committing. There are no open dependents on Packagist, so you are effectively maintaining a fork in practice.
  • No native Laravel facade or auto-discovery. Everything is manual container binding, as shown above. There are no events, no queue metrics, no Horizon-style dashboard. If you need observability, wrap send/readFrame and log frames yourself.
  • readFrame() blocks until the timeout expires. The default read timeout is often effectively forever; always call setReadTimeout() and treat a null return as "no message, try again" rather than as an error.
  • Persistent messages require both header and broker config. persistent => 'true' is honored by ActiveMQ but silently dropped by some brokers. Do not rely on it for exactly-once semantics.
  • Destination prefix is broker-dependent. ActiveMQ wants /queue/ or /topic/. RabbitMQ's STOMP adapter is stricter and rejects /topic/ in some versions. Get the destination format right before chasing phantom delivery bugs.
  • Binary payloads need content-length. Without it, STOMP frames are NUL-terminated and any \x00 in the body will truncate your message. For JSON/text it's fine; for attachments always set the header.
  • ack mode matters. ack => 'client' requires an explicit ack() per frame; 'auto' risks message loss if the process dies mid-handling. Use client for anything with side effects.
  • Reconnect handling is your job. The socket will drop. Wrap connect() in a supervised command with exponential backoff, or listen for StompException in your loop and rebuild the connection.
  • Transaction IDs are connection-scoped. Do not attempt to commit a transaction on a freshly reconnected socket; you will get a broker error (and lose the sends you thought were pending).
  • Extension point is thin. The class is not designed for subclassing. If you need retries, dead-letter routing, or circuit breaking, put it in a wrapper service rather than patching the vendor code — otherwise composer update will overwrite it.
  • Consider the alternative. Unless you specifically need STOMP 1.2 on an existing broker, evaluate stomp-php (active fork, PHP 8 support, PSR-4) or a broker-native client before adopting this one for a new project.
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.
3mdikram/worldmoneywords
snowsoft/config
itmosoft/laravel-subscriptions
larva/laravel-ai-qwen
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