How to accommodate Amazon FIFO SQS in Laravel queue?
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 extendsIlluminate\Queue\SqsQueue
but supports SQS FIFO. - Create a new
SqsFifoConnector
class that extendsIlluminate\Queue\Connectors\SqsConnector
that would establish a connection usingSqsFifoQueue
. - Create a new
SqsFifoServiceProvider
that registers theSqsFifoConnector
to Laravel's queue manager. - Add
SqsFifoServiceProvider
to yourconfig/app.php
. - Update
config/queue.php
to use the new SQS FIFO Queue driver.
Example:
Create a new
SqsFifoQueue
class that extendsIlluminate\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 extendsIlluminate\Queue\Connectors\SqsConnector
that would establish a connection usingSqsFifoQueue
.<?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 theSqsFifoConnector
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 yourconfig/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