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.
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.