[Laravel] Queues를 이용한 비동기 프로그래밍

[Laravel] Queues를 이용한 비동기 프로그래밍 updated_at: 2024-10-08 16:22

[Laravel] Queues를 이용한 비동기 프로그래밍

라라벨은 queues를 활용하면 대량의 메일 발송이나 시간이 많이 걸리는 프로세스등을 백그라운드로 처리할 수 있다.
설정파일은 config/queue.php 파일이다
지원하는 queue로는 sync, database, beanstalkd, sqs, redis 등등이 있으며
여기서는 database를 활용한 큐를 처리하는 예제를 설명드릴텐데 전반적인 그림은 아래와 같다.

  • 사용자가 프로그램실행 > jobs 테이블에 queue 저장 > queue:work가 저장된 queue 처리

라라벨의 Queues 사용하기

1. jobs 테이블 생성하기

php artisan queue:table
> Migration created successfully!

jobs라는 테이블이 생성됩니다. 생성을 수동으로 하시려면 아래 query를 이용하시기 바랍니다.

CREATE TABLE `jobs` (
	`id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
	`queue` VARCHAR(255) NOT NULL COLLATE 'utf8mb4_unicode_ci',
	`payload` LONGTEXT NOT NULL COLLATE 'utf8mb4_unicode_ci',
	`attempts` TINYINT(3) UNSIGNED NOT NULL,
	`reserved_at` INT(10) UNSIGNED NULL DEFAULT NULL,
	`available_at` INT(10) UNSIGNED NOT NULL,
	`created_at` INT(10) UNSIGNED NOT NULL,
	PRIMARY KEY (`id`) USING BTREE,
	INDEX `jobs_queue_index` (`queue`) USING BTREE
)
COLLATE='utf8mb4_unicode_ci'
ENGINE=InnoDB
;

2. QUEUE_CONNECTION (.env) 설정

QUEUE_CONNECTION=database

config/queue.php 파일을 보면 default가 sync로 설정되어 있고 다양한 connection이 있음을 확인 할 수 있다
저는 database를 사용할 예정이므로 .env 파일에서 QUEUE_CONNECTION=database 로 변경하였습니다.
아래 database에서 table을 위에서 만든 jobs를 사용하고 있음을 알 수 있습니다.

'default' => env('QUEUE_CONNECTION', 'sync'),
'connections' => [
  ..........
    'database' => [
        'driver' => 'database',
        'table' => 'jobs',
        ..........,
    ],
  ],

3. Job 제작

php artisan make:job FirstJob

명령을 실행하면 app/Jobs 폴더안에 FirstJob.php파일이 생성된다.
이곳에서 우리는 필요한 프로그램을 하여야 하는데 먼저 기본적인 모양만 보여드리기 위해 생성된 파일 그대로를 나열하였습니다.

..........
class FirstJob implements ShouldQueue
{
  use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
  ..........
  public function __construct()
  {
  }
  public function handle()
  {
  }
}

4. Dispatch the Job

dispatch 를 사용하면 jobs 테이블에 queue가 저장된다.

use App\Jobs\FirstJob;
..........
class MyController extends Controller
{
  ..........
  public function MyMethod(Request $request) {
    FirstJob::dispatch($request->somedata);
    ..........
  }
}

위와 같이 Job을 생성하여 처리하는 방식외에도 Notificaion, Mail등에서는 자체적으로 queue에 저장하는 방식을 제공한다.
Notification의 경우는 implements ShouldQueue로서 지원하고
Mail의 경우 ->queue(new..) 를 사용함으로 가능한다. 각각에 대한 예제는 각 chapter에서 다시 설명 드리겠습니다.

5. jobs 테이블에 데이타가 들어갔는지 확인

위의 코드를 실행하면 위에서 만든 jobs 테이블에 데이타가 들어가게 됩니다.

id : 1
queue: default
payload: {"uuid":"f6b8dd54-5639-4a47-bcb9-b8cea590806c","displayName":"App\\Jobs\\FirstJob","job":"Illuminate\\Queue\\CallQueuedHandler@call","maxTries":null,"maxExceptions":null,"failOnTimeout":false,"backoff":null,"timeout":null,"retryUntil":null,"data":{"commandName":"App\\Jobs\\FirstJob","command":"O:17:\"App\\Jobs\\FirstJob\":10:{s:3:\"job\";N;s:10:\"connection\";N;s:5:\"queue\";N;s:15:\"chainConnection\";N;s:10:\"chainQueue\";N;s:19:\"chainCatchCallbacks\";N;s:5:\"delay\";N;s:11:\"afterCommit\";N;s:10:\"middleware\";a:0:{}s:7:\"chained\";a:0:{}}"}}
attempts: 0
............

6. Queue Worker 실행하기

위의 jobs 테이블에 들어가 있는 데이타는 라라벨의 artisan 명령어인 queue:work 혹은 queue:listen으로 실행이 되며 실행후 현재 jobs테이블의 데이타는 사라진다. 실패하면 failed_jobs라는 테이블에 실패한 처리내용이 들어가게 됩니다.

queue:work vs queue:listen

work 는 Job의 프로그램이 변경되면 다시 실행하여야 정삭으로 작동되지만 listen은 바로 적용된다.

  • work: 안정적인 운영이 필요로 하는 경우(주의: work로 실행할 경우 job이 변경되면 다시 재시작하여야 한다.)
  • listen: 변경된 소스를 실시간 적용(개발중인 경우 이 것이 유리)
php artisan queue:listen // php artisan queue:work

> [2024-03-21 18:03:39][1] Processing: App\Jobs\FirstJob
> [2024-03-21 18:03:39][1] Processed:  App\Jobs\FirstJob

위의 방식은 터미널을 닫으면 실행되지 않으므로 아래와 같이 백그라운드로 실행하여야 한다.
아래는 supervisor 혹은 nohup을 사용할때의 각각의 방식에 대해 간략하게 설명드립니다.

supervisor를 이용한 백그라운드 실행
conf 파일 생성

/etc/supervisor/conf.d 에서 laravel-worker.conf 파일을 생성후 아래와 같이 입력합니다.

[program:laravel-worker]
process_name=%(program_name)s_%(process_num)02d
; command=php /home/forge/app.com/artisan queue:work sqs --sleep=3 --tries=3 --max-time=3600
command=php /home/forge/app.com/artisan queue:work --sleep=3 --tries=3 --max-time=3600
autostart=true
autorestart=true
stopasgroup=true
killasgroup=true
;user=forge // 실제 리눅스의 계정을 입력
numprocs=8
redirect_stderr=true
stdout_logfile=/home/forge/app.com/worker.log
stopwaitsecs=3600
sudo supervisorctl reread // 위에 작성된 conf 파일을 리로드
sudo supervisorctl update // 위에 작성된 conf 파일을 업데이트
sudo supervisorctl start "laravel-worker:*" // conf 파일 실행
sudo supervisorctl restart "laravel-worker:*" //stop 이후 start 실행
sudo supervisorctl stop "laravel-worker:*" // 종료시
sudo supervisorctl status // 상태확인
nohup을 이용한 백그라운드 실행

nohup 다루기 참조

nohup php artisan queue:work --daemon &
nohup php artisan queue:work --daemon >> storage/logs/laravel.log & // (추천) 라라벨 로그에 같이 처리할 경우

nohup php artisan queue:listen &
nohup php artisan queue:listen >> storage/logs/laravel.log & // 라라벨 로그에 같이 처리할 경우

7. Job 파일

4.에서 FirstJob::dispatch($request->somedata);를 호출하면 아래처럼 처리하여야 합니다.

..........
class FirstJob implements ShouldQueue
{
  use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
  ..........
  private $somedata;
  public function __construct($somedata) //  FirstJob::dispatch($request->somedata) 를 받음
  {
    $this->somedata = $somedata;
  }
  public function handle()
  {
    // $this->somedata 를 이용하여 이곳에서 프로그램 처리
  }
}
평점을 남겨주세요
평점 : 5.0
총 투표수 : 1

질문 및 답글