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

Laravel Ratchet Laravel Package

askedio/laravel-ratchet

Laravel Ratchet integrates the Ratchet WebSocket library into Laravel, making it easy to run real-time WebSocket servers alongside your app. Configure and start a server with Artisan, handle connections and messages, and push live updates without extra infrastructure.

View on GitHub
Deep Wiki
Context7

Getting Started

Reality check first: the last tagged release is from November 2018, so this is a Laravel 5.4–6-era package built on cboden/ratchet (PHP 7.x). Before investing time, run composer require askedio/laravel-ratchet on your actual Laravel version. On Laravel 9+ you will almost certainly hit dependency conflicts against newer symfony/* and react/event-loop constraints. If you're on a modern stack, treat this as a legacy-project tool and evaluate beyondcode/laravel-websockets or Soketi instead.

Assuming the install resolves:

  1. Install and publish

    composer require askedio/laravel-ratchet
    php artisan vendor:publish --provider="Askedio\LaravelRatchet\Providers\LaravelRatchetServiceProvider"
    

    Laravel 5.5+ auto-discovers the provider; older versions need it added to config/app.php. Publishing gives you config/ratchet.php.

  2. Point the config at your server class. The published config exposes the server class, host, and port (typically env-driven):

    // config/ratchet.php
    return [
        'class' => \App\Ratchet\EchoServer::class,
        'host'  => env('RATCHET_HOST', '0.0.0.0'),
        'port'  => env('RATCHET_PORT', 8080),
    ];
    
  3. Write the server. Extend the package's RatchetServer base class and implement the Ratchet lifecycle methods. The base class gives you Laravel's container, so app(...), facades, and Eloquent all work inside handlers:

    namespace App\Ratchet;
    
    use Askedio\LaravelRatchet\RatchetServer;
    use Ratchet\ConnectionInterface;
    
    class EchoServer extends RatchetServer
    {
        protected $clients;
    
        public function __construct()
        {
            parent::__construct();
            $this->clients = new \SplObjectStorage;
        }
    
        public function onOpen(ConnectionInterface $conn)
        {
            $this->clients->attach($conn);
        }
    
        public function onMessage(ConnectionInterface $from, $msg)
        {
            foreach ($this->clients as $client) {
                if ($client !== $from) {
                    $client->send($msg);
                }
            }
        }
    
        public function onClose(ConnectionInterface $conn)
        {
            $this->clients->detach($conn);
        }
    
        public function onError(ConnectionInterface $conn, \Exception $e)
        {
            $conn->close();
        }
    }
    
  4. Run it: php artisan ratchet:serve. Most versions also accept --host= / --port= overrides. Then point a browser at it:

    const ws = new WebSocket('ws://localhost:8080');
    ws.onmessage = e => console.log(e.data);
    

First useful use case: an echo/broadcast loop as above, then immediately replace the echo with a targeted fan-out (next section). That is the smallest thing that proves the pipe works end to end.

Implementation Patterns

Connection registry with identity. The single most common pattern is a SplObjectStorage (or an array keyed by $conn->resourceId) that stores metadata on connect. Authenticate during onOpen by reading $conn->httpRequest->getUri()->getQuery() for a token, or by requiring a first {"type":"auth","token":"..."} message before the connection is allowed to do anything else. Store the resolved user_id on the connection object (Ratchet connections are plain objects — you can set arbitrary properties).

Rooms/channels. Keep a second map of channel => SplObjectStorage. On subscribe, attach; on send, iterate only that channel. Detach in onClose from every map you touched in onOpen — this is the second-most-common source of leaks after forgetting to detach at all.

Bridging HTTP requests → WebSocket pushes. The Ratchet process has no way to know about a normal HTTP request. The two practical patterns:

  • Polling a queue in onTimer: dispatch a Laravel event from your controller, push a job, and have the server drain a Redis/database queue on a periodic timer ($this->loop->addPeriodicTimer(1, fn () => ...)). Simple, at the cost of ~1s latency.
  • Pub/sub: Redis pub/sub or ZeroMQ (react/zmq + Ratchet's WAMP components) from both sides. Lower latency, more wiring. The package does not provide this bridge — you build it.

Dispatch Laravel events from handlers. Because the container is available, event(new MessageReceived($from, $payload)) inside onMessage lets the rest of the app (listeners, broadcasting, logging) react without coupling your socket code to domain logic. This is also the cleanest testability seam: keep business logic in services and events, keep the server class thin.

Per-message validation, per-message try/catch. Wrap each onMessage body in a try/catch (Throwable $e); log and send an error frame back. One uncaught exception in Ratchet can tear down the loop for every connected client, not just the offender.

Heartbeats and pruning. Ratchet frequently doesn't notice a dropped TCP connection. Add an onTimer (or addPeriodicTimer) that pings every client and closes/detaches ones that fail to respond, otherwise your registry grows forever.

Supervisor + reverse proxy. Run one process per port under Supervisor (numprocs=1, autorestart=true, stdout to a log file) and terminate TLS at nginx with proxy_pass plus the Upgrade/Connection: upgrade headers. Do not try to run the event loop behind php-fpm.

Gotchas and Tips

  • No request lifecycle. Auth::user(), sessions, middleware, and request() do not exist per message. Whatever you resolve in onOpen is what you have for the life of the connection. Re-authenticate explicitly if the connection is long-lived.
  • Long-running process = stale dependencies. Eloquent's PDO is dropped by MySQL's wait_timeout after a few hours of idling. Call DB::reconnect() in a periodic timer, or catch Illuminate\Database\QueryException on disconnect and retry. The same applies to Redis connections and anything holding file handles.
  • Anything blocking blocks everyone. A slow query, an HTTP call to a third-party API, or sleep() inside onMessage freezes all clients. Push real work onto the queue and let the timer fan out results.
  • Restart on every deploy. The process holds old code in memory; config:cache and composer install don't affect a running server. Make Supervisor reload part of your deploy script.
  • Read config, not env, at runtime. Once config:cache has run, env() inside the server returns null. Always go through config('ratchet.*') in handlers.
  • Detach before you iterate destructively. Removing from an SplObjectStorage while iterating it will skip entries. Collect connections to drop into an array, then detach after the loop.
  • Origin checking. Ratchet's origin check is easy to leave wide open. If the package doesn't expose it, wrap the component in Ratchet\Http\OriginCheck or validate the Origin header yourself in onOpen — otherwise any site can open a socket as your users.
  • Debugging without a stack trace. echo/Log::info go to Supervisor's stdout — tail that log, not laravel.log alone. Use websocat or the browser devtools Network → WS tab to inspect frames; there is no built-in inspector.
  • Shutdown signal handling. Without the pcntl extension, Ctrl+C often leaves the port held. php -m | grep pcntl before you blame the package for Address already in use.
  • Where to extend. The RatchetServer base class is the extension point: override onOpen/onMessage/onClose/onError/onTimer, and call parent::__construct() if you add a constructor. If you need custom handshake behavior, drop down to a plain Ratchet MessageComponentInterface component and register it via the same config class key — the package is thin enough that this is usually easier than fighting the wrapper.
  • Pin your dependencies. Because the package is unmaintained, lock it (and cboden/ratchet) in composer.json and keep an eye on transitive security advisories. Budget time for a migration if the project has a long life ahead.
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.
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
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core