Laravel의 큐 시스템은 무거운 작업을 비동기적으로 처리하여 애플리케이션의 응답 시간을 개선할 수 있게 해준다. 하지만 큐를 사용할 때는 여러 가지 고려해야 할 사항들이 있다.
1. 작업 시간 관리
타임아웃 설정
class ProcessPodcast implements ShouldQueue
{
public $timeout = 120; // 2분
public $tries = 3; // 재시도 횟수
public function handle()
{
// 긴 작업 처리
}
}작업 시간 초과 시 대처 방법
class ProcessPodcast implements ShouldQueue
{
public function handle()
{
// 1. 작업을 더 작은 단위로 나누기
$chunks = $this->data->chunk(100);
foreach ($chunks as $chunk) {
ProcessChunk::dispatch($chunk);
}
// 2. 진행 상황 저장
Cache::put('process_progress', 50);
}
public function retryUntil()
{
// 최대 24시간까지만 재시도
return now()->addHours(24);
}
}2. 데이터 직렬화 문제
잘못된 방식
class SendWelcomeEmail implements ShouldQueue
{
private $user;
private $temporaryData;
public function __construct(User $user)
{
// 잘못된 예: private 속성은 직렬화되지 않는다
$this->user = $user;
$this->temporaryData = Session::get('temp_data');
}
}올바른 방식
class SendWelcomeEmail implements ShouldQueue
{
public $user;
public array $additionalData;
public function __construct(User $user, array $data)
{
// public 속성 사용
$this->user = $user;
$this->additionalData = $data;
}
public function handle()
{
if (!$this->user) {
return; // 모델이 삭제된 경우 처리
}
}
}3. 메모리 관리
메모리 누수 방지
class ProcessLargeDataset implements ShouldQueue
{
public function handle()
{
// 1. 청크 단위로 처리
User::chunk(100, function ($users) {
foreach ($users as $user) {
// 처리 로직
}
// 메모리 해제
unset($users);
gc_collect_cycles();
});
// 2. 커서 사용
foreach (User::cursor() as $user) {
// 처리 로직
}
}
}4. 동시성 문제
레이스 컨디션 방지
class UpdateUserStatus implements ShouldQueue
{
public function handle()
{
// 잘못된 방식
$user = User::find($this->userId);
$user->status = 'active';
$user->save();
// 올바른 방식
DB::transaction(function () {
$user = User::lockForUpdate()->find($this->userId);
$user->status = 'active';
$user->save();
});
}
}유니크 작업 처리
class ProcessPayment implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
public function uniqueId()
{
return $this->orderId; // 주문당 하나의 작업만 큐에 들어간다
}
}5. 실패 처리
실패 감지와 로깅
class SendNewsletter implements ShouldQueue
{
public function failed($exception)
{
// 실패 로깅
Log::error('뉴스레터 발송 실패', [
'exception' => $exception->getMessage(),
'user_id' => $this->userId
]);
// 관리자에게 알림
Notification::send(
Admin::all(),
new JobFailedNotification($this, $exception)
);
}
}실패 후 정리
class ProcessUpload implements ShouldQueue
{
public function failed($exception)
{
// 임시 파일 정리
Storage::delete($this->temporaryPath);
// 진행 상태 초기화
Cache::forget('upload_progress_' . $this->fileId);
}
}6. 의존성 주입 주의사항
잘못된 방식
class SendNotification implements ShouldQueue
{
private $service;
public function __construct(NotificationService $service)
{
// 잘못됨: 직렬화할 수 없는 의존성
$this->service = $service;
}
}올바른 방식
class SendNotification implements ShouldQueue
{
public function handle(NotificationService $service)
{
// 올바름: 핸들러에서 의존성 주입받기
$service->send();
}
}7. 큐 모니터링과 관리
실패한 작업 모니터링
// failed_jobs 테이블 확인
$failedJobs = DB::table('failed_jobs')
->orderBy('failed_at', 'desc')
->get();
// Horizon 대시보드 사용 (권장)
class HorizonServiceProvider extends HorizonApplicationServiceProvider
{
protected function gate()
{
Gate::define('viewHorizon', function ($user) {
return $user->isAdmin();
});
}
}결론
Laravel의 큐 시스템을 사용할 때는 다음 사항들을 특히 주의해야 한다:
- 작업 시간은 항상 제한을 두고 관리한다
- 데이터 직렬화 시 public 속성만 사용한다
- 메모리 관리를 철저히 한다
- 동시성 문제를 고려하여 설계한다
- 실패 처리를 반드시 구현한다
- 의존성 주입은 handle 메소드에서 한다
- 큐 작업을 모니터링하고 관리한다
이러한 주의사항들을 잘 지키면 안정적이고 효율적인 큐 시스템을 구축할 수 있다.