Loading...

This is taking longer than expected.

Real time with Reverb

Switch on the optional WebSocket server so add-on payments and the notification bell update on their own, locally and on a Ploi server.

The kit ships with real time switched off. With it off, everything works as it always has: the add-on screens ask the server every few seconds while a payment is waiting, and the notification bell shows what there was when the page loaded. The live support chat is the exception: it needs real time and is not offered without it. Switch it on and these react within a second, with no polling:

Screen With real time off With real time on
Add-on catalogue and add-on detail, after paying Polls every 3 seconds (catalogue) or 5 seconds (detail) until Stripe confirms the payment No polling. Every Stripe webhook about the account tells its open billing screens to check, and the confirmation shows as soon as the webhook lands
Notification bell in the top bar Counter and list are loaded with the page A new notification updates the counter and the list in every open tab of the person it was sent to, and only of that person
Live support chat, for the customer and on the team's chats page Not available: a customer who opens it reads "We have a technical problem right now" and, when tickets are on, is offered Send a ticket Every change to a chat reaches the customer who owns it and everyone on the team who can answer chats. The guide «Live support chat», available when the live chat is on, explains it

The decision is the application's, not each screen's: real time is on when the broadcasting connection is reverb, and off with any other value. That connection is BROADCAST_CONNECTION when the environment writes it, and the project's own default when it does not (see Switch it on or off). There is no fallback: if Reverb is on and its server is down, nothing breaks, the screens simply stop updating on their own until it is back (a payment is still confirmed; the person sees it on reload).

Reverb is a process of its own that runs on the same server as the application, so it shares that server's memory and processor. It is light, but it is one more thing to keep alive, which is why the kit leaves the choice to each product.

What is involved

  • Server side. laravel/reverb is the WebSocket server. Broadcasting is immediate (ShouldBroadcastNow), so it does not need the queue worker.
  • Browser side. laravel-echo and pusher-js are bundled in resources/js/bootstrap.js. The layout only hands the browser the connection settings when the person is signed in and real time is on, so a visitor without a session, or any page with real time off, never opens a connection.
  • Channels. Three private channels, all authorised at POST /broadcasting/auth: App.Models.User.{id} (only that user, declared in routes/channels.php) carries notification.received and, for the customer of a live chat, support-chat.updated; support-chats (whoever can answer tickets, while the live chat is on, declared in routes/channels.php) carries support-chat.updated to the team; billing-account.{id} (only someone who can manage that billing account, declared by Billing Core) carries billing-account.updated.

Try it locally

  1. Make sure the dependencies are installed: composer install and npm install (laravel/reverb, laravel-echo and pusher-js come with the kit).

  2. Add to your local .env. The three app values are any random strings you choose; php -r "echo bin2hex(random_bytes(16));" makes one.

    BROADCAST_CONNECTION=reverb
    REVERB_APP_ID=local
    REVERB_APP_KEY=a-random-string
    REVERB_APP_SECRET=another-random-string
    REVERB_HOST=weblabor-base.test
    REVERB_PORT=8080
    REVERB_SCHEME=https
    

    Use your own site name in REVERB_HOST. Do not run php artisan reverb:install or php artisan install:broadcasting: the kit is already wired, and both commands rewrite files it owns.

  3. Start the server, naming the secured Herd or Valet site so Reverb serves TLS with its certificate (an https page cannot open a plain ws:// connection):

    php artisan reverb:start --hostname=weblabor-base.test --debug
    
  4. php artisan config:clear, then npm run dev (or npm run build) and reload the page. With --debug the terminal prints each connection and each message.

  5. Check both cases. Buy an add-on with a Stripe test card and the confirmation appears as soon as the webhook arrives (forward webhooks with stripe listen locally), with no checkSubscriptionStatus or checkPending requests repeating in the network tab. Then make a notification reach someone, for example answer their ticket from another account, and their bell changes without a reload while another signed-in person's does not.

Switch it on or off

On: set BROADCAST_CONNECTION=reverb with the REVERB_* values, start the Reverb process, and run php artisan config:clear (or php artisan optimize if you cache the configuration). Off: set BROADCAST_CONNECTION=null (or remove it, null is the default), run the same command, and stop the process. Nothing needs rebuilding: the browser reads the settings from the page, not from the bundle.

BROADCAST_CONNECTION always wins when the environment writes it. Without it, the connection is the project's default, one line at the top of config/broadcasting.php:

$projectDefault = 'null';

The kit ships it as null, so real time stays off until a server switches it on. A product that wants it on everywhere Reverb is set up, for example to offer the live support chat by default, writes 'reverb' there. Then each environment decides on its own credentials:

Environment Result
No BROADCAST_CONNECTION, REVERB_APP_ID, REVERB_APP_KEY and REVERB_APP_SECRET all set Real time on, with nothing written in that .env
No BROADCAST_CONNECTION, any of the three missing or empty Real time off, as if the default were null: the application, artisan and the tests start, and the add-on screens keep polling
BROADCAST_CONNECTION=null, or any other connection That connection, credentials or not
BROADCAST_CONNECTION=reverb with the three credentials Real time on
BROADCAST_CONNECTION=reverb with any of the three missing The application does not start, and the error names the Reverb variables that are empty

The last case does not quietly fall back to null: writing reverb and forgetting the credentials is a mistake in that environment, and the error says which values are missing instead of failing deep inside the Pusher client. The tests always run with BROADCAST_CONNECTION=null, whatever your local .env says; a test that needs real time switches it on itself.

Deploy it on Ploi

Ploi keeps processes alive with Supervisor and serves the site with Nginx. It can run Reverb for you, but it does not write the Nginx block that forwards the WebSocket traffic: that part is yours.

  1. Supervisor. Reverb runs as a Ploi daemon, and daemons run under Supervisor, so Supervisor has to be installed and running on the server. A server that already runs the queue worker as a Ploi daemon has it; on a new one, check it among the server's services before adding the daemon.

  2. The Reverb process. In the server's Daemons, add one:

    Field Value
    Command php /home/ploi/your-domain.com/artisan reverb:start --host=127.0.0.1 --port=8080
    User ploi
    Processes 1

    It listens only on the server itself, port 8080; Nginx is the only thing that reaches it.

  3. Nginx. In the site's Manage, open the Nginx configuration and add, inside the server block that listens on 443, the two routes Reverb uses: /app for the browsers' WebSocket connections and /apps for the application publishing events.

    location /app {
        proxy_http_version 1.1;
        proxy_set_header Host $http_host;
        proxy_set_header Scheme $scheme;
        proxy_set_header SERVER_PORT $server_port;
        proxy_set_header REMOTE_ADDR $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "Upgrade";
        proxy_pass http://127.0.0.1:8080;
    }
    
    location /apps {
        proxy_http_version 1.1;
        proxy_set_header Host $http_host;
        proxy_set_header Scheme $scheme;
        proxy_set_header SERVER_PORT $server_port;
        proxy_set_header REMOTE_ADDR $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "Upgrade";
        proxy_pass http://127.0.0.1:8080;
    }
    

    Save it; Ploi tests and reloads Nginx.

  4. Environment. In the site's environment, with your own random values:

    BROADCAST_CONNECTION=reverb
    REVERB_APP_ID=your-app-id
    REVERB_APP_KEY=your-app-key
    REVERB_APP_SECRET=your-app-secret
    REVERB_HOST=your-domain.com
    REVERB_PORT=443
    REVERB_SCHEME=https
    

    REVERB_HOST, REVERB_PORT and REVERB_SCHEME are the public address, the one Nginx answers on, used both by the browsers and by the application to publish. The process itself keeps listening on 127.0.0.1:8080.

  5. Deploy script. The usual commands already rebuild the application's assets (npm ci and npm run build), which is what bundles Echo; keep them. Add, after php artisan queue:restart:

    php artisan reverb:restart
    

    Like the queue worker, Reverb keeps the code it started with in memory, and this is what makes Supervisor start it again with the new release.

The Ploi steps are documented here but not tested by the kit. After the first deploy, open a page signed in and check in the browser's network tab that the connection to wss://your-domain.com/app/... opens with status 101.

Back