0

I'm implementing a real-time stock opname (inventory check) feature using Laravel and Ratchet WebSocket.

I want to broadcast a message to all connected WebSocket clients when an API endpoint is hit, for example:

// Laravel controller
public function startStockOpname(Request $request) {
    Redis::publish("stock-opname.{$branchCode}", json_encode([
        'message' => 'Stock Opname Started',
        'role' => 'auditor',
        'branch_code' => $branchCode,
    ]));
} 

On the other side, the WebSocket server (Ratchet) is subscribing to the Redis channels and then broadcasting messages to clients.

This is the flow I aim for:

Frontend ➜ API call to Laravel ➜ Laravel publishes via Redis ➜ WebSocket server receives ➜ Broadcast to WebSocket clients

But it doesn't work.

  • The WebSocket server starts fine and subscribes using psubscribe('stock-opname.*')

  • But when I hit the Laravel API, no message is received in the WebSocket server.

  • The clients never receive the message.

  • I tried dumping the message in Laravel — it's publishing, but the WebSocket server does not respond.

However, if I send the message directly from the frontend via websocket.send(), everything works perfectly and all clients receive the message.

this.websocket.onmessage = (event) => {
                const data = JSON.parse(event.data);
                console.log('Message received:', data);

                // Jika auditor memulai stock opname
                if (data.message === 'Stock Opname Started/Resumed' && data.role === 'auditor') {
                    this.isDisabledStart = false;
                    this.remainingSeconds = 60;
                    this.startCountdownTimer();
                }
            };

So now I'm confused:

Questions:

  1. When using Ratchet in Laravel, is Redis mandatory if I want to send messages from Laravel (API/controller) to WebSocket clients?

  2. Is Redis not needed if the frontend directly sends messages to the WebSocket server via .send()?

  3. Why would Redis::publish() in Laravel fail to trigger a broadcast in Ratchet, even though everything seems connected?

1 Answer 1

0

Clarification on Your Questions

1. Is Redis mandatory to communicate from Laravel to WebSocket clients?

Yes, Redis or any other message broker is essential if Laravel and the WebSocket server are running in separate processes. Laravel cannot directly call methods in the Ratchet server; it must use a broker like Redis to pass messages between these isolated components.

2. Is Redis not needed if the frontend sends messages via .send()?

Correct. In this case, the frontend communicates directly with the WebSocket server. Redis is unnecessary because there is no Laravel interaction involved in message delivery.

3. Why does Redis::publish() in Laravel not trigger any response in Ratchet?

The WebSocket server likely uses a blocking subscription (psubscribe) that:

  • Stops the event loop from executing.

  • Prevents handling of WebSocket connections or Redis messages in real-time.

  • Lacks proper asynchronous integration with the Ratchet loop.

Additionally, Laravel and Ratchet may be connected to different Redis instances, ports, or databases, which should be verified.

Solution

Use an Asynchronous Redis Client Compatible with the Ratchet Event Loop

The correct way to receive Redis messages in a non-blocking way is by using the react/redis package, which is fully compatible with the Ratchet event loop (ReactPHP). This allows the WebSocket server to simultaneously listen to Redis and handle WebSocket client connections.

Step-by-Step Implementation

1. Install Required Packages

Install react/redis and Ratchet (if not already installed):

composer require clue/redis-react
composer require cboden/ratchet

2. Update Your WebSocket Server

Here is a simplified example of a WebSocket server using Ratchet and react/redis to handle Redis messages and broadcast them to WebSocket clients:

use Ratchet\MessageComponentInterface;
use Ratchet\ConnectionInterface;
use React\EventLoop\Factory as LoopFactory;
use React\Socket\Server as SocketServer;
use Ratchet\Server\IoServer;
use Ratchet\Http\HttpServer;
use Ratchet\WebSocket\WsServer;
use Clue\React\Redis\Factory as RedisFactory;

class StockOpnameServer implements MessageComponentInterface
{
    public $clients;

    public function __construct()
    {
        $this->clients = new \SplObjectStorage;
    }

    public function onOpen(ConnectionInterface $conn)
    {
        $this->clients->attach($conn);
    }

    public function onMessage(ConnectionInterface $from, $msg) {}

    public function onClose(ConnectionInterface $conn)
    {
        $this->clients->detach($conn);
    }

    public function onError(ConnectionInterface $conn, \Exception $e)
    {
        $conn->close();
    }

    public function broadcast($data)
    {
        foreach ($this->clients as $client) {
            $client->send($data);
        }
    }
}

// Create ReactPHP loop
$loop = LoopFactory::create();

// Create the WebSocket server instance
$stockServer = new StockOpnameServer();

// Set up WebSocket server
$socket = new SocketServer('0.0.0.0:8080', $loop);
$server = new IoServer(
    new HttpServer(
        new WsServer($stockServer)
    ),
    $socket,
    $loop
);

// Subscribe to Redis
$redisFactory = new RedisFactory($loop);
$redisFactory->createSubscriber('127.0.0.1:6379')->then(function ($redis) use ($stockServer) {
    $redis->psubscribe('stock-opname.*');
    $redis->on('pmessage', function ($pattern, $channel, $message) use ($stockServer) {
        $stockServer->broadcast($message);
    });
});

// Run the loop
$loop->run();

This example:

  • Starts a WebSocket server.

  • Subscribes to all Redis channels that match stock-opname.*.

  • Forwards any Redis message received to all connected WebSocket clients.

3. Verify Laravel Redis Configuration

Ensure that Laravel and your WebSocket server are using the same Redis configuration (host, port, database index):

Check in Laravel: config/database.php

'redis' => [
    'client' => 'phpredis',
    'default' => [
        'host' => env('REDIS_HOST', '127.0.0.1'),
        'port' => env('REDIS_PORT', 6379),
        'database' => env('REDIS_DB', 0),
    ],
],

Ensure that REDIS_HOST, REDIS_PORT, and REDIS_DB match what the WebSocket server is using.

Checklist

  • Use react/redis in the WebSocket server.

  • Ensure Laravel and the WebSocket server use the same Redis instance.

  • Integrate Redis subscription into the same event loop as Ratchet.

  • Replace blocking psubscribe() with async handling from react/redis.

  • Confirm Redis::publish() sends to correct channel (e.g., stock-opname.branch1).

  • Confirm Redis receives messages by testing with redis-cli.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.