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:

  1. Create a new SqsFifoQueue class that extends Illuminate\Queue\SqsQueue but supports SQS FIFO.
  2. Create a new SqsFifoConnector class that extends Illuminate\Queue\Connectors\SqsConnector that would establish a connection using SqsFifoQueue.
  3. Create a new SqsFifoServiceProvider that registers the SqsFifoConnector to Laravel's queue manager.
  4. Add SqsFifoServiceProvider to your config/app.php.
  5. Update config/queue.php to use the new SQS FIFO Queue driver.

Example:

  1. 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');
        }
    }
    
  2. 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', '')
            );
        }
    }
    
  3. 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;
                });
            });
        }
    }
    
  4. Add SqsFifoServiceProvider to your config/app.php.

    <?php
    
    return [
        'providers'     => [
            ...
            SqsFifoServiceProvider::class,
        ],
    ];
    
  5. 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