큐(Queue) 시스템
DB 기반 커스텀 큐 — 잡 추가(push) · 처리(process) · 실패 재시도(retry) 전체 흐름을 실습합니다.
0
대기(Pending)
0
처리 중
0
완료(Done)
0
실패(Failed)
잡 추가 (Push)
잡 처리 (Process)
잡을 추가하고 "다음 잡 처리" 버튼을 눌러보세요.
대기/처리 중 잡
대기 중인 잡이 없습니다.
완료된 잡 (최근 10개)
완료된 잡이 없습니다.
잡 클래스 정의
// app/Jobs/BaseJob.php
abstract class BaseJob
{
protected array $payload;
public function __construct(array $payload = [])
{
$this->payload = $payload;
}
abstract public function handle(): array;
}
// app/Jobs/EmailNotificationJob.php
class EmailNotificationJob extends BaseJob
{
public function handle(): array
{
$to = $this->payload['to'];
$subject = $this->payload['subject'];
// 실제 이메일 발송 로직
// mail($to, $subject, $body);
return [
'result' => 'success',
'message' => "이메일 발송 완료 → {$to}",
];
}
}
잡 추가 & 처리
$queue = new \App\Libraries\QueueManager();
// ① 잡 추가 (즉시)
$id = $queue->push(
EmailNotificationJob::class,
['to' => 'user@example.com', 'subject' => '알림'],
'emails' // 큐 이름
);
// ② 지연 실행 (30초 후)
$queue->push(
ReportGenerateJob::class,
['period' => 'monthly'],
'reports',
30 // delaySeconds
);
// ③ 다음 잡 처리 (CLI 워커에서 루프)
$result = $queue->processNext('emails');
// $result: ['success'=>true, 'job'=>'...', 'result'=>[...]]
// ④ 실패 잡 재시도
$queue->retry($failedJobId);
// ⑤ 통계
$stats = $queue->stats('emails');
// ['pending'=>2, 'processing'=>1, 'done'=>15, 'failed'=>1]
CLI 워커 패턴 (실무에서는 이렇게 실행)
// app/Commands/QueueWorker.php
class QueueWorker extends BaseCommand
{
protected $name = 'queue:work';
protected $description = '큐 워커 실행';
public function run(array $params): void
{
$queue = $params[0] ?? 'default';
$manager = new \App\Libraries\QueueManager();
$this->write("워커 시작: {$queue} 큐");
while (true) {
$result = $manager->processNext($queue);
if ($result['success']) {
$this->write("[✓] {$result['job']} 처리 완료");
} elseif (isset($result['failed']) && $result['failed']) {
$this->write("[✗] {$result['job']} 최종 실패: {$result['exception']}");
} else {
// 잡 없음 → 1초 대기
sleep(1);
}
}
}
}
// 실행: php spark queue:work emails
운영 팁: 실무에서는
Supervisor 또는 systemd로 워커 프로세스를 관리합니다.
프로세스가 죽으면 자동 재시작되도록 설정하세요.
큐 처리 흐름
- Push — 웹 요청에서 잡 데이터를
queue_jobs테이블에 삽입 - Worker — CLI 워커가 주기적으로
processNext()호출 - Processing — 잡 상태를
processing으로 변경 후handle()실행 - Done / Retry — 성공 시
done, 실패 시 재시도 카운트 증가 - Failed — 최대 재시도 초과 시
queue_failed_jobs로 이동
웹 요청
└── QueueManager::push()
└── INSERT queue_jobs (status=pending)
CLI 워커 (루프)
└── QueueManager::processNext()
├── SELECT pending job
├── UPDATE status=processing
├── Job::handle()
│ ├── 성공 → UPDATE status=done
│ └── 실패 → attempts++
│ ├── attempts < max → status=pending (재시도 대기)
│ └── attempts >= max → INSERT queue_failed_jobs
│ DELETE queue_jobs
DB 스키마
queue_jobs
| 컬럼 | 타입 | 설명 |
|---|---|---|
| id | INTEGER PK | 잡 고유 ID |
| queue | VARCHAR | 큐 이름 (default/emails/…) |
| job_class | VARCHAR | 처리할 잡 클래스 FQCN |
| payload | TEXT (JSON) | 잡 파라미터 |
| status | VARCHAR | pending/processing/done |
| attempts | INTEGER | 시도 횟수 |
| max_attempts | INTEGER | 최대 재시도 횟수 |
| available_at | INTEGER | 실행 가능 시각 (Unix) |
queue_failed_jobs
| 컬럼 | 설명 |
|---|---|
| exception | 실패 원인 메시지 |
| failed_at | 실패 시각 (Unix) |
| + queue/job_class/payload/attempts | 원본 잡 정보 |
실제 큐 라이브러리
이 예제는 학습용 커스텀 구현입니다. 실무에서는 다음을 고려하세요:
- Redis + Laravel Queues — 고성능, 실시간
- Amazon SQS — 클라우드 관리형
- RabbitMQ — AMQP 프로토콜
- codeigniter4/queue — CI4 공식 패키지 (DB/Redis 드라이버)