본문 바로가기
← 패키지 목록

Laravel Queue Rabbitmq

vladimir-yuldashev/laravel-queue-rabbitmq

제출자 Laravel Korea Discovery Bot
최신 v13.3.2라이센스 MIT
큐·작업

Laravel Queue용 RabbitMQ 드라이버입니다. Laravel Horizon을 지원합니다.

Laravel Queue RabbitMQ 사용 가이드

Latest Stable Version Build Status Total Downloads License

이 패키지는 Laravel의 큐 시스템에서 RabbitMQ를 드라이버로 사용할 수 있도록 지원합니다. Redis나 데이터베이스 드라이버 대신, 메시지 브로커로 검증된 RabbitMQ를 큐 백엔드로 활용하고 싶을 때 유용합니다.

지원 정책

최신 버전에만 새로운 기능이 추가됩니다. 버그 수정은 아래 정책에 따라 제공됩니다.

패키지 버전Laravel 버전버그 수정 지원 종료일
1392023년 8월 8일Documentation

설치

Composer를 통해 패키지를 설치합니다.

composer require vladimir-yuldashev/laravel-queue-rabbitmq

이 패키지는 별도 설정 없이 자동으로 등록됩니다.

기본 설정

config/queue.php 파일에 RabbitMQ 커넥션을 추가합니다.

NOTE

아래 설정은 RabbitMQ 커넥션/드라이버가 동작하기 위한 최소 구성입니다.

'connections' => [ // ... 'rabbitmq' => [ 'driver' => 'rabbitmq', 'hosts' => [ [ 'host' => env('RABBITMQ_HOST', '127.0.0.1'), 'port' => env('RABBITMQ_PORT', 5672), 'user' => env('RABBITMQ_USER', 'guest'), 'password' => env('RABBITMQ_PASSWORD', 'guest'), 'vhost' => env('RABBITMQ_VHOST', '/'), ], // ... ], // ... ], // ... ],

로컬 개발 환경에서는 Docker로 RabbitMQ를 띄우는 경우가 많습니다. 관리 콘솔까지 함께 사용하려면 rabbitmq:3-management 이미지를 사용하면 http://localhost:15672에서 큐 상태를 시각적으로 확인할 수 있어 편리합니다.

큐 옵션 설정 (선택 사항)

커넥션 설정에 큐 옵션을 추가로 지정할 수 있습니다. 이 커넥션으로 생성되는 모든 큐는 여기서 지정한 속성을 갖게 됩니다.

지연된(delayed) 메시지에 우선순위를 부여하고 싶다면 아래와 같이 옵션을 추가합니다.

  • queue_max_priority를 생략하면 사용 시 기본값 2가 적용됩니다.
'connections' => [ // ... 'rabbitmq' => [ // ... 'options' => [ 'queue' => [ // ... 'prioritize_delayed' => false, 'queue_max_priority' => 10, ], ], ], // ... ],

라우팅 키(routing-key)를 사용해 익스체인지(exchange)로 메시지를 발행하고 싶다면 다음과 같이 옵션을 추가합니다.

  • exchange를 생략하면 RabbitMQ는 라우팅 키에 대해 amq.direct 익스체인지를 사용합니다.
  • routing-key를 생략하면 기본적으로 queue 이름이 라우팅 키로 사용됩니다.
  • 라우팅 키에 %s를 사용하면 큐 이름으로 치환됩니다.

NOTE

익스체인지와 라우팅 키를 함께 사용하는 경우, 큐와 바인딩(binding)은 직접 생성해야 하는 경우가 대부분입니다.

'connections' => [ // ... 'rabbitmq' => [ // ... 'options' => [ 'queue' => [ // ... 'exchange' => 'application-x', 'exchange_type' => 'topic', 'exchange_routing_key' => '', ], ], ], // ... ],

Laravel은 기본적으로 실패한 Job을 데이터베이스에 저장합니다. 하지만 경우에 따라 실패한 메시지를 다른 프로세스에서 별도로 처리하고 싶을 수 있습니다. 이때는 실패한 메시지를 특정 익스체인지나 큐로 재전달하도록 RabbitMQ에 지시할 수 있습니다.

  • exchange를 생략하면 RabbitMQ는 라우팅 키에 대해 amq.direct 익스체인지를 사용합니다.
  • routing-key를 생략하면 기본적으로 큐 이름 뒤에 .failed가 붙은 값이 라우팅 키로 사용됩니다.
  • 라우팅 키에 %s를 사용하면 큐 이름으로 치환됩니다.

NOTE

실패 Job용 익스체인지와 라우팅 키를 사용할 경우, 해당 익스체인지/큐와 바인딩은 직접 생성해야 하는 경우가 대부분입니다.

'connections' => [ // ... 'rabbitmq' => [ // ... 'options' => [ 'queue' => [ // ... 'reroute_failed' => true, 'failed_exchange' => 'failed-exchange', 'failed_routing_key' => 'application-x.%s', ], ], ], // ... ],

Horizon 지원

8.0 버전부터 이 패키지는 Laravel Horizon을 기본적으로 지원합니다. 먼저 Horizon을 설치한 뒤 RABBITMQ_WORKER 값을 horizon으로 설정하세요.

Horizon은 워커가 발생시키는 이벤트를 기반으로 동작합니다. 이 이벤트들은 메시지/Job에 어떤 작업이 이루어졌는지를 Horizon에 알려주는 역할을 합니다.

이 라이브러리는 Horizon을 지원하지만, 설정 파일에서 Horizon과 호환되는 Queue API를 사용하도록 Laravel에 명시적으로 알려주어야 합니다.

'connections' => [ // ... 'rabbitmq' => [ // ... /* Laravel Horizon을 사용하려면 "horizon"으로 설정하세요. */ 'worker' => env('RABBITMQ_WORKER', 'default'), ], // ... ],

커스텀 RabbitMQJob 클래스 사용하기

때로는 다른 애플리케이션이 발행한 메시지를 처리해야 하는 경우가 있습니다. 이런 메시지들은 대부분 Laravel의 Job 페이로드 스키마를 따르지 않습니다. 문제는 이런 메시지를 받았을 때 Laravel 워커가 실제로 실행할 Job이나 클래스를 판단할 수 없다는 점입니다.

이럴 때는 기본 제공되는 RabbitMQJob::class를 확장하고, 큐 커넥션 설정에서 직접 만든 클래스를 지정하면 됩니다. 설정에 job 키로 커스텀 클래스명을 지정하면, 브로커에서 가져온 모든 메시지가 해당 클래스로 래핑됩니다.

설정 예시:

'connections' => [ // ... 'rabbitmq' => [ // ... 'options' => [ 'queue' => [ // ... 'job' => \App\Queue\Jobs\RabbitMQJob::class, ], ], ], // ... ],

커스텀 Job 클래스 예시:

<?php namespace App\Queue\Jobs; use VladimirYuldashev\LaravelQueueRabbitMQ\Queue\Jobs\RabbitMQJob as BaseJob; class RabbitMQJob extends BaseJob { /** * Job을 실행합니다. * * @return void */ public function fire() { $payload = $this->payload(); $class = WhatheverClassNameToExecute::class; $method = 'handle'; ($this->instance = $this->resolve($class))->{$method}($this, $payload); $this->delete(); } }

또는 페이로드에 추가 속성을 넣고 싶다면 다음과 같이 작성할 수 있습니다.

<?php namespace App\Queue\Jobs; use VladimirYuldashev\LaravelQueueRabbitMQ\Queue\Jobs\RabbitMQJob as BaseJob; class RabbitMQJob extends BaseJob { /** * Job의 디코딩된 본문을 가져옵니다. * * @return array */ public function payload() { return [ 'job' => 'WhatheverFullyQualifiedClassNameToExecute@handle', 'data' => json_decode($this->getRawBody(), true) ]; } }

JSON 형식이 아니거나 job 키가 없는 원시(raw) 메시지를 처리하고 싶다면, getName 메서드에 대한 스텁을 추가해야 합니다.

<?php namespace App\Queue\Jobs; use Illuminate\Support\Facades\Log; use VladimirYuldashev\LaravelQueueRabbitMQ\Queue\Jobs\RabbitMQJob as BaseJob; class RabbitMQJob extends BaseJob { public function fire() { $anyMessage = $this->getRawBody(); Log::info($anyMessage); $this->delete(); } public function getName() { return ''; } }

커스텀 Connection 클래스 사용하기

기본 제공되는 PhpAmqpLib\Connection\AMQPStreamConnection::class 또는 PhpAmqpLib\Connection\AMQPSLLConnection::class를 확장하여, 커넥션 설정에서 직접 만든 클래스를 지정할 수 있습니다. 설정에 connection 키로 커스텀 클래스명을 지정하면, 모든 커넥션이 해당 클래스를 사용하게 됩니다.

설정 예시:

'connections' => [ // ... 'rabbitmq' => [ // ... 'connection' = > \App\Queue\Connection\MyRabbitMQConnection::class, ], // ... ],

커스텀 Worker 클래스 사용하기

VladimirYuldashev\LaravelQueueRabbitMQ\Queue\RabbitMQQueue를 확장하면 직접 만든 RabbitMQQueue::class를 사용할 수 있습니다. 이후 RABBITMQ_WORKER 값을 \App\Queue\RabbitMQQueue::class로 설정하여 Laravel이 이 클래스를 사용하도록 지정합니다.

NOTE

Worker 클래스는 반드시 VladimirYuldashev\LaravelQueueRabbitMQ\Queue\RabbitMQQueue를 상속해야 합니다.

'connections' => [ // ... 'rabbitmq' => [ // ... /* 커스텀 클래스를 사용하려면 해당 클래스로 지정하세요. */ 'worker' => \App\Queue\RabbitMQQueue::class, ], // ... ],
<?php namespace App\Queue; use VladimirYuldashev\LaravelQueueRabbitMQ\Queue\RabbitMQQueue as BaseRabbitMQQueue; class RabbitMQQueue extends BaseRabbitMQQueue { // ... }

예시: 재연결(reconnect) 구현하기

연결이 끊어졌을 때 RabbitMQ에 다시 연결하고 싶다면, publishBasiccreateChannel 등의 메서드를 오버라이드할 수 있습니다.

NOTE

아래 코드는 모범 사례(best practice)라기보다 구현 방식을 보여주기 위한 예시입니다.

<?php namespace App\Queue; use PhpAmqpLib\Exception\AMQPChannelClosedException; use PhpAmqpLib\Exception\AMQPConnectionClosedException; use VladimirYuldashev\LaravelQueueRabbitMQ\Queue\RabbitMQQueue as BaseRabbitMQQueue; class RabbitMQQueue extends BaseRabbitMQQueue { protected function publishBasic($msg, $exchange = '', $destination = '', $mandatory = false, $immediate = false, $ticket = null): void { try { parent::publishBasic($msg, $exchange, $destination, $mandatory, $immediate, $ticket); } catch (AMQPConnectionClosedException|AMQPChannelClosedException) { $this->reconnect(); parent::publishBasic($msg, $exchange, $destination, $mandatory, $immediate, $ticket); } } protected function publishBatch($jobs, $data = '', $queue = null): void { try { parent::publishBatch($jobs, $data, $queue); } catch (AMQPConnectionClosedException|AMQPChannelClosedException) { $this->reconnect(); parent::publishBatch($jobs, $data, $queue); } } protected function createChannel(): AMQPChannel { try { return parent::createChannel(); } catch (AMQPConnectionClosedException) { $this->reconnect(); return parent::createChannel(); } } }

기본 큐(Default Queue)

Laravel에서 큐가 별도로 지정되지 않은 경우, 커넥션은 기본값인 default 큐를 사용합니다. 커넥션 설정에 아래와 같은 파라미터를 추가하면 기본 큐 이름을 변경할 수 있습니다.

'connections' => [ // ... 'rabbitmq' => [ // ... 'queue' => env('RABBITMQ_QUEUE', 'default'), ], // ... ],

Heartbeat

기본적으로 커넥션은 heartbeat 설정값 0으로 생성됩니다. 설정을 변경하면 heartbeat 값을 조정할 수 있습니다.

'connections' => [ // ... 'rabbitmq' => [ // ... 'options' => [ // ... 'heartbeat' => 10, ], ], // ... ],

SSL 보안 연결

RabbitMQ 서버와 보안 연결(SSL)이 필요하다면, 아래와 같은 추가 설정 옵션이 필요합니다.

'connections' => [ // ... 'rabbitmq' => [ // ... 'secure' = > true, 'options' => [ // ... 'ssl_options' => [ '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), ], ], ], // ... ],

데이터베이스 커밋 이후 이벤트 발생

데이터베이스 트랜잭션의 모든 커밋이 완료된 이후에 Laravel 워커가 이벤트를 발생시키도록 지정할 수 있습니다.

'connections' => [ // ... 'rabbitmq' => [ // ... 'after_commit' => true, ], // ... ],

지연 연결(Lazy Connection)

기본적으로 커넥션은 지연(lazy) 방식으로 생성됩니다. 즉, 실제로 필요한 시점이 되어야 연결이 맺어집니다. 이 동작을 원치 않는다면 다음과 같이 설정을 끌 수 있습니다.

'connections' => [ // ... 'rabbitmq' => [ // ... 'lazy' = > false, ], // ... ],

네트워크 프로토콜

기본적으로 커넥션에는 tcp 프로토콜이 사용됩니다. 다른 프로토콜을 사용하고 싶다면 설정 옵션에 값을 추가하면 됩니다. 사용 가능한 프로토콜: tcp, ssl, tls

'connections' => [ // ... 'rabbitmq' => [ // ... 'network_protocol' => 'tcp', ], // ... ],

네트워크 타임아웃

네트워크 타임아웃은 옵션 파라미터로 설정할 수 있습니다. 모든 값은 초 단위의 실수(float)이며, 0으로 설정하면 타임아웃 없음(무한대)을 의미할 수 있습니다. 아래 예시는 기본값을 보여줍니다.

'connections' => [ // ... 'rabbitmq' => [ // ... 'options' => [ // ... 'connection_timeout' => 3.0, 'read_timeout' => 3.0, 'write_timeout' => 3.0, 'channel_rpc_timeout' => 0.0, ], ], // ... ],

Octane 지원

13.3.0 버전부터 이 패키지는 Laravel Octane을 기본적으로 지원합니다. 먼저 Octane을 설치한 뒤, Octane 설정 파일에서 rabbitmq 커넥션을 warm(사전 로드) 대상에 포함하는 것을 잊지 마세요.

참고: https://github.com/vyuldashev/laravel-queue-rabbitmq/issues/460#issuecomment-1469851667

Laravel에서 사용하기

설정을 마쳤다면 Laravel의 Queue API를 그대로 사용하면 됩니다. 다른 큐 드라이버를 사용해 본 경험이 있다면 추가로 변경할 것은 없습니다. Queue API 사용법을 잘 모른다면 Laravel 공식 문서를 참고하세요: http://laravel.com/docs/queues

Lumen에서 사용하기

Lumen에서는 bootstrap/app.php에 서비스 프로바이더를 직접 등록해야 합니다.

$app->register(VladimirYuldashev\LaravelQueueRabbitMQ\LaravelQueueRabbitMQServiceProvider::class);

메시지 소비하기

메시지를 소비(consume)하는 방법은 두 가지가 있습니다.

  1. Laravel 기본 제공 명령어인 queue:work. 이 명령어는 내부적으로 basic_get을 사용합니다. 여러 개의 큐를 동시에 소비해야 한다면 이 방식을 사용하세요.

  2. 이 패키지가 제공하는 rabbitmq:consume 명령어. 이 명령어는 basic_consume을 사용하며, basic_get 방식보다 약 2배 더 높은 성능을 보입니다. 다만 여러 큐를 동시에 소비하는 기능은 지원하지 않습니다.

실무 팁: 큐가 하나뿐이고 처리량이 중요한 서비스라면 rabbitmq:consume을, 여러 큐를 유연하게 운영해야 하는 환경이라면 queue:work를 선택하는 것이 일반적입니다.

테스트

docker-compose를 사용해 RabbitMQ 테스트 환경을 구성합니다.

docker compose up -d

테스트 스위트는 다음 명령어로 실행할 수 있습니다.

# 스타일 테스트와 유닛 테스트를 모두 실행composer test# 스타일 테스트만 실행composer test:style# 유닛 테스트만 실행composer test:unit

스타일 테스트에서 오류가 발생했다면, 아래 명령어로 대부분의 문제를 자동으로 수정할 수 있습니다.

composer fix:style

기여하기

버그를 발견하거나 이슈를 등록하는 방식으로 이 패키지에 기여할 수 있습니다. 이슈나 풀 리퀘스트를 작성할 때는 대상 패키지 버전을 함께 명시해 주세요. (예: [5.2] 지연 Job에서 치명적 오류 발생)