phplaravelherokuwebsocketpusher

laravel echo does not send the message


I created a real-time chat using pusher and laravel-echo, but in production on the heroku app, the pusher doesn't give any errors, it doesn't give any errors in the console, however, the messages are not sent. Locally it works normally, except if you add hsHost to the Echo wsHost object:

import.meta.env.VITE_PUSHER_HOST.

Bootstrap.js:

 window.Echo = new Echo({
   broadcaster: 'pusher',
   key: import.meta.env.VITE_PUSHER_APP_KEY,
   cluster: import.meta.env.VITE_PUSHER_APP_CLUSTER ?? 'sa1',    
   wsPort: import.meta.env.VITE_PUSHER_PORT ?? 80,
   wssPort: import.meta.env.VITE_PUSHER_PORT ?? 443,
   forceTLS: (import.meta.env.VITE_PUSHER_SCHEME ?? 'https') === 'https',
   enabledTransports: ['ws', 'wss'],

 });

broadicating.php

 'pusher' => [
      'driver' => 'pusher',
      'key' => env('PUSHER_APP_KEY'),
      'secret' => env('PUSHER_APP_SECRET'),
      'app_id' => env('PUSHER_APP_ID'),
      'options' => [
           'cluster' => env('PUSHER_APP_CLUSTER'),     
           'port' => env('PUSHER_PORT', 443),
           'scheme' => env('PUSHER_SCHEME', 'https'),
           'encrypted' => true,
           'useTLS' => env('PUSHER_SCHEME', 'https') === 'https',
       ],
       'client_options' => [
                // Guzzle client options: https://docs.guzzlephp.org/en/stable/request-options.html
       ],
   ],

Events broadcast:

class SendPrivate implements ShouldBroadcast
{
    use Dispatchable, InteractsWithSockets, SerializesModels;

    /**
     * Create a new event instance.
     */
    
     private $mensagem;
    private $user;
    public function __construct($mensagem , User $user)
    {
        $this->mensagem = $mensagem;
        $this->user = $user;
    }

    /**
     * Get the channels the event should broadcast on.
     *
     * @return array<int, \Illuminate\Broadcasting\Channel>
     */
    public function broadcastOn(): array
    {
        return [
           new PrivateChannel('User.'. $this->user->id)
        ];
    }
    public function broadcastWith()
    {
       return  [
            'mensagem' => $this->mensagem,
       ];
    }
}

Vue:

Echo.private('User.' + idLogado.value).listen('SendPrivate', (e) => {  
 
   messages.value.push(e.mensagem);
   scrollBottom();
});

Heroku reveal variables

VITE_PUSHER_APP_KEY= ********  
VITE_PUSHER_APP_CLUSTER = mt1  
VITE_PUSHER_HOST = ws-mt1.pusher.com  
VITE_PUSHER_PORT = 443  
VITE_PUSHER_SCHEME = https 

Pusher credentials env

PUSHER_APP_KEY= ******** 
PUSHER_APP_SECRET= ********  
PUSHER_APP_CLUSTER = mt1  
PUSHER_HOST = ws-mt1.pusher.com  
PUSHER_PORT = 443  
PUSHER_SCHEME = https 

Some solutions I saw say the problem was with the cluster, but I changed the cluster and it didn't work, I also added and removed the host from window.echo and it didn't solve it in both cases. Locally it only works if I implement a queue. I run this command in the terminal:

php artisan queue:work database --daemon --tries=5

So I implemented a queue in Heroku, but it didn't work either.

worker php artisan queue:listen

No errors appear in the console.


Solution

  • I was facing the same problem a time ago, I fixed it editing the broadcasting.php file inside config folder:

        'pusher' => [
            'driver' => 'pusher',
            'key' => env('PUSHER_APP_KEY'),
            'secret' => env('PUSHER_APP_SECRET'),
            'app_id' => env('PUSHER_APP_ID'),
            'options' => [
                'cluster' => env('PUSHER_APP_CLUSTER'),
                'encrypted' => true,
                'useTLS' => true,
                'encryption_master_key_base64' => env('PUSHER_MASTER_KEY')
            ],
        ],
    

    For the encryption_master_key you can generate one using openssl rand -base64 32 in a terminal, you'll need openssl, set the key in your .env file and should be good to go.

    In the JS part, this is how I've did it:

    import Echo from 'laravel-echo';
    import Pusher from 'pusher-js/with-encryption';
    
    window.Pusher = Pusher;
    
    window.Echo = new Echo({
        broadcaster: 'pusher',
        key: import.meta.env.VITE_PUSHER_APP_KEY,
        cluster: import.meta.env.VITE_PUSHER_APP_CLUSTER,
        wsHost: window.location.hostname,
        wsPort: 6001,
        forceTLS: false,
        disableStats: false,
        encrypted: true,
    });
    

    In your .env file, set the APP_URL to the complete url to your app, set the PUSHER_HOST to the Heroku host url. So, don't forget to add all those environment variables to Heroku. You can use ngrok to forward your local project in order to test prior to deploy in Heroku.