Pusher not receiving events from Laravel 5.2 broadcasting - php

I am using Laravel 5.2 and php 7. I am testing this on a local Mac OSX environment. I am having no trouble pinging other services or making requests with php. I configured my application by editing broadcasting.php and .env with my api details.
broadcasting.php
'default' => env('BROADCAST_DRIVER', 'pusher'),
'connections' => [
'pusher' => [
'driver' => 'pusher',
'key' => env('mykey'),
'secret' => env('mysecret'),
'app_id' => env('myappid'),
],
...
and in .env
...
CACHE_DRIVER=file
SESSION_DRIVER=file
QUEUE_DRIVER=redis
BROADCAST_DRIVER=pusher
PUSHER_KEY=mykey
PUSHER_SECRET=mysecret
PUSHER_APP_ID=myappid
...
I created a TestEvent like so
<?php
namespace App\Events;
use App\Events\Event;
use Illuminate\Queue\SerializesModels;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
class TestEvent extends Event implements ShouldBroadcast
{
use SerializesModels;
public $data;
public function __construct()
{
$this->data = array(
'power'=> '10'
);
}
public function broadcastOn()
{
return ['test_channel'];
}
}
I then call on the event like so
Event::fire(new TestEvent());
The event shows up and is processed in redis
[2016-02-04 10:06:18] Processed: Illuminate\Broadcasting\BroadcastEvent
[2016-02-04 10:08:44] Processed: Illuminate\Broadcasting\BroadcastEvent
[2016-02-04 10:11:14] Processed: Illuminate\Broadcasting\BroadcastEvent
[2016-02-04 10:11:59] Processed: Illuminate\Broadcasting\BroadcastEvent
[2016-02-04 10:14:22] Processed: Illuminate\Broadcasting\BroadcastEvent
[2016-02-04 11:17:04] Processed: Illuminate\Broadcasting\BroadcastEvent
[2016-02-04 11:38:14] Processed: Illuminate\Broadcasting\BroadcastEvent
But nothing shows up in pusher when viewing the debug console. So it seems that the event is never being sent to pusher for some reason. I also checked my timezone settings to make sure that was not an issue. There are no errors in my in the laravel log file when the event is broadcasted.
How can I solve this problem? Is there a good way to debug and see if there is actually a request being made to pusher?

This might not fix the issue and maybe you changed your details for the question, but if your .env is like this:
PUSHER_KEY=mykey
PUSHER_SECRET=mysecret
PUSHER_APP_ID=myappid
Shouldn't the code for your pusher credentials look like this:
'pusher' => [
'driver' => 'pusher',
'key' => env('PUSHER_KEY'),
'secret' => env('PUSHER_SECRET'),
'app_id' => env('PUSHER_APP_ID'),
],
It's referencing the value in your code, not the key!

Related

Laravel Websockets raises a BroadcastException "Invalid auth signature provided"

I'm trying to add websockets support to my Laravel 9 application. I've read in their documentation that I could run an open source server on my own instead of relying on commercial solutions. With that in mind, I decided to give Beyondcode's Laravel Websockets a try. My application runs on PHP 8.2, using Laravel 9.19 and Laravel Websockets 1.13, communicating with the sockets through the Pusher Channels HTTP PHP Library 7.2.
Laravel Websockets is meant to match the server's settings with the client's by using the same naming scheme on both ends and launching off the same codebase.
This is how I've set up my .env file:
APP_NAME="My app"
APP_ENV=local
APP_KEY=<redacted>
APP_DEBUG=true
BROADCAST_DRIVER=pusher
PUSHER_APP_ID="${APP_NAME}"
PUSHER_APP_KEY="${APP_KEY}"
PUSHER_APP_SECRET="${APP_KEY}${APP_NAME}"
PUSHER_HOST=ws-server
PUSHER_PORT=6001
PUSHER_SCHEME=http
PUSHER_APP_CLUSTER=mt1
My docker-compose.yml file contains the following content:
version: "3.9"
services:
queue:
build: .
environment:
- ROLE=queue
volumes:
- .:/var/www
ws-server:
build: .
environment:
- ROLE=ws-server
volumes:
- .:/var/www
ports:
- 6001:6001
The ws-server service has an entrypoint script which runs the following command on an infinite loop: php artisan websockets:serve --host 0.0.0.0 --port 6001
Within config/websockets.php I've left everything as it comes out of the box, just so you can rest assured, this is how my apps array looks like:
'apps' => [
[
'id' => env('PUSHER_APP_ID'),
'name' => env('APP_NAME'),
'key' => env('PUSHER_APP_KEY'),
'secret' => env('PUSHER_APP_SECRET'),
'path' => env('PUSHER_APP_PATH'),
'capacity' => null,
'enable_client_messages' => false,
'enable_statistics' => true,
],
]
The queue service hosts a class called TerminalUpdated, which looks like this:
<?php
namespace App\Events;
use App\Models\User;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Log;
class TerminalUpdated implements ShouldBroadcast
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public string $id;
public string $newLine;
/**
* Create a new event instance.
*
* #return void
*/
public function __construct(string $id, string $newLine)
{
$this->id = $id;
$this->newLine = $newLine;
}
/**
* Get the channels the event should broadcast on.
*
* #return \Illuminate\Broadcasting\Channel|array
*/
public function broadcastOn()
{
return new PrivateChannel('console.' . $this->id);
}
}
Another script running within the service mentioned above executes the following sentence:
<?php
$id = '123';
$line = 'This is a line of text.';
TerminalUpdated::dispatch(
$this->id, // id
$line // newLine
);
?>
Everything looks more or less okay to me, yet I'm getting the following exception:
[2023-01-19 01:05:09] local.ERROR: Pusher error: {"error":"Invalid auth signature provided."}. {"exception":"[object] (Illuminate\\Broadcasting\\BroadcastException(code: 0): Pusher error: {\"error\":\"Invalid auth signature provided.\"}. at /var/www/vendor/laravel/framework/src/Illuminate/Broadcasting/Broadcasters/PusherBroadcaster.php:164)
"}
I don't seem to be able to figure out where is it even trying to generate the signature mentioned in the exception shown above.
I've already tried the following possible fixes:
Restart the server
Reset the framework's caches and temporary files by calling php artisan optimize:clear
This is how I configured the WebSocket:
In the websocket.php file :
apps => [
[
'id' => env('PUSHER_APP_ID'),
'name' => env('APP_NAME'),
'key' => env('PUSHER_APP_KEY'),
'secret' => env('PUSHER_APP_SECRET'),
'path' => env('PUSHER_APP_PATH'),
'capacity' => null,
'enable_client_messages' => false,
'enable_statistics' => true,
],
],
In broadcasting.php I have:
'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'),
'useTLS' => false,
'encrypted' => false,
'host'=> '127.0.0.1',
'port' => 6001,
'scheme' => 'http',
],
],
I hope it helps you out.
The problem is that PUSHER_APP_ID can't contain spaces. Using a string without spaces instead fixes the issue. It looks like the library just can't translate the spaces to the expected URL encoding.

Using multiple SQS queues on a single connection - Laravel

I am trying to understand if my issue is a limitation with Laravel's logic or an issue in my config. I have this in my queue.php file
'connections' => [
'sqs' => [
'driver' => 'sqs',
'key' => env('AWS_ACCESS_KEY_ID'),
'secret' => env('AWS_SECRET_ACCESS_KEY'),
'token' => env('AWS_SESSION_TOKEN'),
'prefix' => env('SQS_PREFIX'),
'region' => env('AWS_REGION'),
],
],
Now, when I try to this command
php artisan queue:work sqs --tries 3 --queue='high-priority'
I would expect it to process the outstanding jobs in the 'high-priority' queue, however instead it throws this exception
ErrorException : Undefined index: queue
at {redacted}/vendor/laravel/framework/src/Illuminate/Queue/Connectors/SqsConnector.php:26
22| $config['credentials'] = Arr::only($config, ['key', 'secret', 'token']);
23| }
24|
25| return new SqsQueue(
> 26| new SqsClient($config), $config['queue'], $config['prefix'] ?? ''
27| );
28| }
29|
30| /**
Now I can see that laravel is trying to construct a new SqsClient using the config value in key of queue, so in this case it seems that to use multiple queues here I would need to define an individual connection for every queue (which seems completely overkill).
So really, wondering if this is a limitation or if I misunderstand how the config is being passed into the construction of the SqsClient.

Laravel 5.2 queue job keeps on retrying

class ProcessComment extends Job implements ShouldQueue
{
use InteractsWithQueue;
/**
* #var int
*/
public $tries = 1;
public function handle(Somedepency $someDependency) {
// method body....
// tries to connect to a database
// deliberately provide the wrong database url so that the job .
// will throw exception and hence faild
}
The problem is that when i run php artisan queue:work --daemon or php artisan queue:work --daemon --tries=1
The tries option doesn't seem to work. In my redis queue I continuously see the attempts it tries to make like. It should try only one time and if the job failed, just ignore that job and move ahead.
"EXEC"
1522044746.165780 [0 172.20.0.5:48992] "WATCH" "queues:comments:reserved"
1522044746.166110 [0 172.20.0.5:48992] "ZRANGEBYSCORE" "queues:comments:reserved" "-inf" "1522044746"
1522044746.166718 [0 172.20.0.5:48992] "UNWATCH"
1522044746.167436 [0 172.20.0.5:48992] "LPOP" "queues:comments"
1522044746.168051 [0 172.20.0.5:48992] "ZADD" "queues:comments:reserved" "1522044806" {"some serialized data here ... "attempts: 4"}
and so on
This is my configs/queue.php
'default' => env('QUEUE_DRIVER', 'redis'),
'connections' => [
'redis' => [
'driver' => 'redis',
'connection' => 'default',
'queue' => 'comments'
],
],
tried to google it alot but couldn't find satisfactory answer.
Thanks

How to use functions in services.php laravel config file

I needed to use a dynamic callback url for socialite so I added the url() function to my services.php file it worked fine(and its still working on my live server) But when tried to start the project locally I get the following error. When I remove the url() method everything works fine please help.
PHP Fatal error: Uncaught ReflectionException: Class log does not exist in /home/fenn/projects/jokwit/vendor/laravel/framework/src/Illuminate/Container/Container.php:734
Stack trace:
#0 /home/fenn/projects/jokwit/vendor/laravel/framework/src/Illuminate/Container/Container.php(734): ReflectionClass->__construct('log')
#1 /home/fenn/projects/jokwit/vendor/laravel/framework/src/Illuminate/Container/Container.php(629): Illuminate\Container\Container->build('log', Array)
#2 /home/fenn/projects/jokwit/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(697): Illuminate\Container\Container->make('log', Array)
#3 /home/fenn/projects/jokwit/vendor/laravel/framework/src/Illuminate/Container/Container.php(849): Illuminate\Foundation\Application->make('log')
#4 /home/fenn/projects/jokwit/vendor/laravel/framework/src/Illuminate/Container/Container.php(804): Illuminate\Container\Container->resolveClass(Object(ReflectionParameter))
#5 /home/fenn/projects/jokwit/vendor/laravel/framework/src/Illuminate/Container/Container.php(7 in /home/fenn/projects/jokwit/vendor/laravel/framework/src/Illuminate/Container/Container.php on line 734
Here is my services.php file
<?php
return [
/*
|--------------------------------------------------------------------------
| Third Party Services
|--------------------------------------------------------------------------
|
| This file is for storing the credentials for third party services such
| as Stripe, Mailgun, Mandrill, and others. This file provides a sane
| default location for this type of information, allowing packages
| to have a conventional place to find your various credentials.
|
*/
'mailgun' => [
'domain' => env('MAILGUN_DOMAIN'),
'secret' => env('MAILGUN_SECRET'),
],
'mandrill' => [
'secret' => env('MANDRILL_SECRET'),
],
'ses' => [
'key' => env('SES_KEY'),
'secret' => env('SES_SECRET'),
'region' => 'us-east-1',
],
'stripe' => [
'model' => App\User::class,
'key' => env('STRIPE_KEY'),
'secret' => env('STRIPE_SECRET'),
],
'facebook' => [
'client_id' => '1700935300171729',
'client_secret' => 'XXXXXXXXXXXXXXXXXXX',
'redirect' => url('/facebook/callback'),
],
'google' => [
'client_id' => 'XXXXXXXXXXXXXXXXXXXXXXXX',
'client_secret' => 'XXXXXXXXXXXXXXXXXXXXXXXX',
'redirect' => url('google/callback'),
],
];
In services.php file
...
'redirect' => 'google/callback',
...
Next create service provider for example ConfigServiceProvider
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
class ConfigServiceProvider extends ServiceProvider
{
/**
* Bootstrap the application services.
*
* #return void
*/
public function boot()
{
//
}
/**
* Register the application services.
*
* #return void
*/
public function register()
{
\Config::set("services.google.redirect", url(\Config::get('services')['google']['redirect']));
}
}
now should work fine
It doesn't work because in production Laravel cached all configuration files and using this cache. In development environment Laravel didn't create cache.
You can check it by commenting url() in config and then running php artisan config:cache command. Uncomment url() part and you'll see error is disappeared.
The best you can do here is to not use Laravel or manually defined functions in config files and find another solution for your problem.

How to accommodate Amazon FIFO SQS in Laravel queue?

Amazon has announced their new FIFO SQS service and I'd like to use it in Laravel Queue to solve some concurrency issues.
I've created several new queues and changed the configurations. However, I got a MissingParameter error which says
The request must contain the parameter MessageGroupId.
So I modified the file vendor/laravel/framework/src/Illuminate/Queue/SqsQueue.php
public function pushRaw($payload, $queue = null, array $options = [])
{
$response = $this->sqs->sendMessage(['QueueUrl' => $this->getQueue($queue), 'MessageBody' => $payload,
'MessageGroupId' => env('APP_ENV', getenv('APP_ENV'))]);
return $response->get('MessageId');
}
public function later($delay, $job, $data = '', $queue = null)
{
$payload = $this->createPayload($job, $data);
$delay = $this->getSeconds($delay);
return $this->sqs->sendMessage([
'QueueUrl' => $this->getQueue($queue), 'MessageBody' => $payload, 'DelaySeconds' => $delay,
'MessageGroupId' => env('APP_ENV', getenv('APP_ENV'))
])->get('MessageId');
}
I'm using APP_ENV as the group ID (it's a single message queue so actually it doesn't matter a lot. I just want everything to be FIFO).
But I'm still getting the same error message. How could I fix it? Any help would be appreciated.
(btw, where has the SDK defined sendMessage? I can find a stub for it but I didn't find the detailed implementation)
I want to point out to others who might stumble across the same issue that, although editing SqsQueue.php works, it will easily be reset by a composer install or composer update. An alternative is to implement a new Illuminate\Queue\Connectors\ConnectorInterface for SQS FIFO then add it to Laravel's queue manager.
My approach is as follows:
Create a new SqsFifoQueue class that extends Illuminate\Queue\SqsQueue but supports SQS FIFO.
Create a new SqsFifoConnector class that extends Illuminate\Queue\Connectors\SqsConnector that would establish a connection using SqsFifoQueue.
Create a new SqsFifoServiceProvider that registers the SqsFifoConnector to Laravel's queue manager.
Add SqsFifoServiceProvider to your config/app.php.
Update config/queue.php to use the new SQS FIFO Queue driver.
Example:
Create a new SqsFifoQueue class that extends Illuminate\Queue\SqsQueue but supports SQS FIFO.
<?php
class SqsFifoQueue extends \Illuminate\Queue\SqsQueue
{
public function pushRaw($payload, $queue = null, array $options = [])
{
$response = $this->sqs->sendMessage([
'QueueUrl' => $this->getQueue($queue),
'MessageBody' => $payload,
'MessageGroupId' => uniqid(),
'MessageDeduplicationId' => uniqid(),
]);
return $response->get('MessageId');
}
}
Create a new SqsFifoConnector class that extends Illuminate\Queue\Connectors\SqsConnector that would establish a connection using SqsFifoQueue.
<?php
use Aws\Sqs\SqsClient;
use Illuminate\Support\Arr;
class SqsFifoConnector extends \Illuminate\Queue\Connectors\SqsConnector
{
public function connect(array $config)
{
$config = $this->getDefaultConfiguration($config);
if ($config['key'] && $config['secret']) {
$config['credentials'] = Arr::only($config, ['key', 'secret']);
}
return new SqsFifoQueue(
new SqsClient($config), $config['queue'], Arr::get($config, 'prefix', '')
);
}
}
Create a new SqsFifoServiceProvider that registers the SqsFifoConnector to Laravel's queue manager.
<?php
class SqsFifoServiceProvider extends \Illuminate\Support\ServiceProvider
{
public function register()
{
$this->app->afterResolving('queue', function ($manager) {
$manager->addConnector('sqsfifo', function () {
return new SqsFifoConnector;
});
});
}
}
Add SqsFifoServiceProvider to your config/app.php.
<?php
return [
'providers' => [
...
SqsFifoServiceProvider::class,
],
];
Update config/queue.php to use the new SQS FIFO Queue driver.
<?php
return [
'default' => 'sqsfifo',
'connections' => [
'sqsfifo' => [
'driver' => 'sqsfifo',
'key' => 'my_key'
'secret' => 'my_secret',
'queue' => 'my_queue_url',
'region' => 'my_sqs_region',
],
],
];
Then your queue should now support SQS FIFO Queues.
Shameless plug: While working on the steps above I've created a laravel-sqs-fifo composer package to handle this at https://github.com/maqe/laravel-sqs-fifo.
FIFO message works in a different way than standard AWS SQS queues.
You need a separate driver for handling FIFO queues.
I had to face the same situation and the below package was a lifesaver.
https://packagist.org/packages/shiftonelabs/laravel-sqs-fifo-queue
in queue.php
'sqs-fifo' => [
'driver' => 'sqs-fifo',
'key' => env('SQS_KEY'),
'secret' => env('SQS_SECRET'),
'prefix' => env('SQS_PREFIX'),
'queue' => env('SQS_QUEUE'),
'region' => env('SQS_REGION'),
'group' => 'default',
'deduplicator' => 'unique',
],
then
dispatch(new TestJob([]))->onQueue('My_Mail_Queue.fifo');
NB:
you need to specify default queue name you are going to use in your application in the .env
SQS_QUEUE=My_Default_queue.fifo
Also, you need to specify all the queue names you are going to use in your application in the listener. (if you are using the same queue name for the whole application, you don't need to specify the queue name in the listener)
php artisan queue:listen --queue=My_Default_queue.fifo,My_Mail_Queue.fifo,My_Message_Queue.fifo
Apart from the MessageGroupId, it needs a MessageDeduplicationId or enabling content-based deduplication.

Categories