RabbitMQ Queue Driver for Laravel
Tags: laravel, rabbitmq, queue, messaging
Published: 2020-03-31 17:38:04

Since [version 6.0 LTS](https://laravel.com/docs/6.x/queues#driver-prerequisites), Laravel has some available drivers for queue connection, such as `database`, `Redis`, `Beanstalkd` and `AWS SQS`. Those external services are great, but there will be a situation when you have to pick the right service for your app in a certain environment. For example, if your app is using AWS as the server then AWS SQS might be the best choice. Maybe there will be a situation when you have to pick another service that not supported (yet) by Laravel and it's the best for your environment and requirement, maybe it's `RabbitMQ`.

Laravel doesn't support RabbitMQ, but there is a package that enables it to be supported. Thanks to [vyuldashev](https://github.com/vyuldashev), [laravel-queue-rabbitmq](https://github.com/vyuldashev/laravel-queue-rabbitmq) is an awesome package to make it happens. I'll show you.

_________________

## Prerequisites

Of course, you have to set RabbitMQ ready on your machine. If you have no idea how to do it, then you can see my post about setting it up in Laradock [here](https://dev.to/dendihandian/rabbitmq-in-laradock-35oo). And for the demo, I will use the simple mail sending example using artisan command that I have practiced [here](https://dev.to/dendihandian/mailhog-in-laradock-1ej6).

_________________

## Installing `laravel-queue-rabbitmq` package

> There is a comment from Francis Igbokwe about the recent version issue. You may want to inspect the comment section below first.

By using `composer` and go to your project directory using CLI, execute this command:

```
composer require vladimir-yuldashev/laravel-queue-rabbitmq
```

Wait until the installation is done.

## Installing AMQP support package

I will give explanation about AMQP later (maybe), but in order to be work between PHP and rabbitmq, you must install the any available AMQP support package. I have tried `AmqpBunny` package and it works. So to install the package, execute this command:

```
composer require enqueue/amqp-bunny:^0.8
```

Wait until the installation is done.

## Configure the queue connection

> see Daniel Ozeh's comment for environment setting issue for the recent version.

In your laravel app's `config/queue.php` file, add the new configuration item for `rabbitmq` inside the `connections` array:

`config/queue.php`:
```php
...

'connections' => [

        ...

        'rabbitmq' => [

            'driver' => 'rabbitmq',

            /*
         * Set to "horizon" if you wish to use Laravel Horizon.
         */
            'worker' => env('RABBITMQ_WORKER', 'default'),

            'dsn' => env('RABBITMQ_DSN', null),

            /*
         * Could be one a class that implements \Interop\Amqp\AmqpConnectionFactory for example:
         *  - \EnqueueAmqpExt\AmqpConnectionFactory if you install enqueue/amqp-ext
         *  - \EnqueueAmqpLib\AmqpConnectionFactory if you install enqueue/amqp-lib
         *  - \EnqueueAmqpBunny\AmqpConnectionFactory if you install enqueue/amqp-bunny
         */

            'factory_class' => \Enqueue\AmqpBunny\AmqpConnectionFactory::class,

            'host' => env('RABBITMQ_HOST', '127.0.0.1'),
            'port' => env('RABBITMQ_PORT', 5672),

            'vhost' => env('RABBITMQ_VHOST', '/'),
            'login' => env('RABBITMQ_LOGIN', 'guest'),
            'password' => env('RABBITMQ_PASSWORD', 'guest'),

            'queue' => env('RABBITMQ_QUEUE', 'default'),

            'options' => [

                'exchange' => [

                    'name' => env('RABBITMQ_EXCHANGE_NAME'),

                    /*
                 * Determine if exchange should be created if it does not exist.
                 */

                    'declare' => env('RABBITMQ_EXCHANGE_DECLARE', true),

                    /*
                 * Read more about possible values at https://www.rabbitmq.com/tutorials/amqp-concepts.html
                 */

                    'type' => env('RABBITMQ_EXCHANGE_TYPE', \Interop\Amqp\AmqpTopic::TYPE_DIRECT),
                    'passive' => env('RABBITMQ_EXCHANGE_PASSIVE', false),
                    'durable' => env('RABBITMQ_EXCHANGE_DURABLE', true),
                    'auto_delete' => env('RABBITMQ_EXCHANGE_AUTODELETE', false),
                    'arguments' => env('RABBITMQ_EXCHANGE_ARGUMENTS'),
                ],

                'queue' => [

                    /*
                 * Determine if queue should be created if it does not exist.
                 */

                    'declare' => env('RABBITMQ_QUEUE_DECLARE', true),

                    /*
                 * Determine if queue should be binded to the exchange created.
                 */

                    'bind' => env('RABBITMQ_QUEUE_DECLARE_BIND', true),

                    /*
                 * Read more about possible values at https://www.rabbitmq.com/tutorials/amqp-concepts.html
                 */

                    'passive' => env('RABBITMQ_QUEUE_PASSIVE', false),
                    'durable' => env('RABBITMQ_QUEUE_DURABLE', true),
                    'exclusive' => env('RABBITMQ_QUEUE_EXCLUSIVE', false),
                    'auto_delete' => env('RABBITMQ_QUEUE_AUTODELETE', false),
                    'arguments' => env('RABBITMQ_QUEUE_ARGUMENTS'),
                ],
            ],

            /*
         * Determine the number of seconds to sleep if there's an error communicating with rabbitmq
         * If set to false, it'll throw an exception rather than doing the sleep for X seconds.
         */

            'sleep_on_error' => env('RABBITMQ_ERROR_SLEEP', 5),

            /*
         * Optional SSL params if an SSL connection is used
         * Using an SSL connection will also require to configure your RabbitMQ to enable SSL. More details can be founds here: https://www.rabbitmq.com/ssl.html
         */

            'ssl_params' => [
                'ssl_on' => env('RABBITMQ_SSL', false),
                'cafile' => env('RABBITMQ_SSL_CAFILE', null),
                'local_cert' => env('RABBITMQ_SSL_LOCALCERT', null),
                'local_key' => env('RABBITMQ_SSL_LOCALKEY', null),
                'verify_peer' => env('RABBITMQ_SSL_VERIFY_PEER', true),
                'passphrase' => env('RABBITMQ_SSL_PASSPHRASE', null),
            ],
        ],
    ],

...
```

And in your laravel app's `.env` file, set parameters into like this:

```env
QUEUE_CONNECTION=rabbitmq

RABBITMQ_HOST=rabbitmq
RABBITMQ_PORT=5672
RABBITMQ_VHOST=/
RABBITMQ_LOGIN=guest
RABBITMQ_PASSWORD=guest
RABBITMQ_QUEUE=default

RABBITMQ_EXCHANGE_NAME=default
RABBITMQ_EXCHANGE_DECLARE=
RABBITMQ_EXCHANGE_TYPE=
RABBITMQ_EXCHANGE_PASSIVE=
RABBITMQ_EXCHANGE_DURABLE=
RABBITMQ_EXCHANGE_AUTODELETE=
RABBITMQ_EXCHANGE_ARGUMENTS=default

RABBITMQ_QUEUE_DECLARE=
RABBITMQ_QUEUE_DECLARE_BIND=
RABBITMQ_QUEUE_PASSIVE=
RABBITMQ_QUEUE_DURABLE=
RABBITMQ_QUEUE_EXCLUSIVE=
RABBITMQ_QUEUE_AUTODELETE=
RABBITMQ_QUEUE_ARGUMENTS=default

RABBITMQ_ERROR_SLEEP=5

RABBITMQ_SSL=
RABBITMQ_SSL_CAFILE=
RABBITMQ_SSL_LOCALCERT=
RABBITMQ_SSL_LOCALKEY=
RABBITMQ_SSL_VERIFY_PEER=
RABBITMQ_SSL_PASSPHRASE=
```

## RabbitMQ connection test and demo

You can check the [rabbitmq management](http://localhost:15672/#/) first to make sure the `Queues` still empty and maybe stop the `php-worker` first if you use it to see the stored queue job later before it executed automatically.

We will use an artisan command to send an email as I practiced before while demonstrating mailhog or php-worker. So, enter the project directory using CLI if you haven't and execute the artisan command:

```
php artisan example:send-mail
```

If you managed to disable the php-worker before, you should see the queue has 1 job ready to be executed:

<img src="https://i.ibb.co/4tg847y/2020-04-01-00h30-25.png" alt="2020-04-01-00h30-25" border="0">

Then start the worker to see if it's working for real.

_________________

Have fun experimenting RabbitMQ with Laravel!
_________________

```
versions used:
 - laravel: 6.0 LTS
 - rabbitmq: 3.8.1
 - laravel-queue-rabbitmq: ^10.0
 - enqueue/amqp-bunny: ^0.8
```