웹 애플리케이션에서는 메일 발송·이미지 리사이즈·외부 API에의 문의 등, 완료까지 수 초가 걸리는 처리가 발생할 수 있습니다.
이를 HTTP 리퀘스트 중에 동기적으로 수행하면, 사용자는 응답이 반환될 때까지 계속 기다려야 합니다.Laravel의 큐를 사용하면, 이러한 무거운 처리를 백그라운드에서 비동기로 실행할 수 있습니다.
리퀘스트는 즉시 응답을 반환하고, 실제의 처리는 워커 프로세스가 별도로 처리해 줍니다.
큐는 데이터베이스·Redis·Amazon SQS 등 여러 백엔드에 대응하고 있습니다.
개발 환경에서는 sync 드라이버를 사용하면, 큐를 사용하지 않고 잡을 즉시 실행할 수 있습니다.
<?phpnamespace App\Jobs;use App\Models\User;use App\Mail\WelcomeMail;use Illuminate\Contracts\Queue\ShouldQueue;use Illuminate\Foundation\Queue\Queueable;use Illuminate\Support\Facades\Mail;class SendWelcomeEmail implements ShouldQueue{ use Queueable; /** * 잡의 인스턴스를 작성 */ public function __construct( public User $user, ) {} /** * 잡을 실행 */ public function handle(): void { Mail::to($this->user->email)->send(new WelcomeMail($this->user)); }}
ShouldQueue 인터페이스를 구현함으로써, 이 잡이 큐에서 비동기 처리됨을 Laravel에 전합니다.
Queueable 트레이트가 잡의 큐 조작에 필요한 메서드를 제공합니다.
컨스트럭터에 Eloquent 모델을 전달하면, Laravel은 자동적으로 ID만을 시리얼라이즈합니다.
실행 시에 데이터베이스로부터 최신 데이터를 다시 취득하기 때문에, 큐의 페이로드가 가벼워집니다.
다수의 독립된 잡을 한 번에 디스패치하는 경우, Bus 파사드의 bulk() 메서드를 사용할 수 있습니다. 배치 처리와 같은 추적이나 콜백이 필요 없는 케이스에 최적입니다.Bus::bulk()는 잡을 설정된 큐 접속과 큐명으로 그룹화하고, 각 그룹을 한꺼번에 큐로 푸시하므로 효율적입니다.
use App\Jobs\ProcessUser;use Illuminate\Support\Facades\Bus;Bus::bulk( $users->map(fn ($user) => new ProcessUser($user)));
Bus::bulk()는 잡을 배치로서 한꺼번에 큐에 송신합니다. 배치 처리(Bus::batch())와는 달리, 진행 추적이나 완료 콜백은 제공되지 않습니다. 독립된 대량의 잡을 심플하게 일괄 송신하고 싶은 경우에 적합합니다.
특정 조건을 만족할 때에 잡을 실행하지 않고 큐로 되돌리고 싶은 경우, Release 미들웨어를 사용하면 간결하게 작성할 수 있습니다.
use Illuminate\Queue\Middleware\Release;/** * 잡이 통과할 미들웨어를 반환 */public function middleware(): array{ return [ // $condition이 true일 때 60초 후에 릴리스 Release::when($this->order->isPending(), releaseAfter: 60), ];}
Release::unless()는 조건이 false일 때에 릴리스합니다.
return [ // 주문이 지불 완료가 아닐 때 60초 후에 릴리스 Release::unless($this->order->isPaid(), releaseAfter: 60),];
use Throwable;public function failed(?Throwable $exception): void{ // 관리자에게 Slack 통지를 보내는 등 // Notification::route('slack', config('app.slack_webhook')) // ->notify(new JobFailedNotification($this, $exception));}
<?phpnamespace App\Jobs;use App\Models\Order;use App\Mail\OrderConfirmed;use Illuminate\Contracts\Queue\ShouldQueue;use Illuminate\Foundation\Queue\Queueable;use Illuminate\Queue\Attributes\Tries;use Illuminate\Queue\Attributes\Timeout;use Illuminate\Support\Facades\Mail;#[Tries(3)]#[Timeout(30)]class SendOrderConfirmation implements ShouldQueue{ use Queueable; public function __construct( public Order $order, ) {} public function handle(): void { Mail::to($this->order->user->email) ->send(new OrderConfirmed($this->order)); }}
3
컨트롤러로부터 디스패치
use App\Jobs\SendOrderConfirmation;public function store(Request $request): RedirectResponse{ $order = Order::create($request->validated()); SendOrderConfirmation::dispatch($order); return redirect()->route('orders.show', $order) ->with('success', '주문을 접수했습니다.');}