반응형
설치·접속: PostgreSQL 설치와 접속
부제: 워커 여러 대가 같은 작업 큐 테이블을 동시에 폴링할 때, 서로 잡은 행은 건너뛰고 각자 다른 행만 집어가게 한다
-- 각 워커가 실행: 남이 잠근 행은 건너뛰고 안 잠긴 것만 3개 집는다
BEGIN;
SELECT id, payload FROM jobs
WHERE status = 'pending'
ORDER BY id
FOR UPDATE SKIP LOCKED
LIMIT 3;
-- ... 처리 후 status 갱신 ...
COMMIT;
=== Worker B (A가 id 1~3을 잡고 있는 중) ===
BEGIN
id | payload
----+---------
4 | job-4
5 | job-5
6 | job-6
(3 rows)
=== Worker A got ===
id | payload
----+---------
1 | job-1
2 | job-2
3 | job-3Worker A가 트랜잭션 안에서 id 13에 행 락을 걸고 아직 커밋하지 않은 사이, Worker B가 같은 쿼리를 던지면 3을 그냥 지나쳐 4~6을 가져온다. 락 대기로 멈추지도, 같은 작업을 중복 처리하지도 않는다. SKIP LOCKED 덕분에 잠긴 1SKIP LOCKED가 없으면 B는 A의 커밋까지 블로킹되고, 그냥 LIMIT만 쓰면 둘 다 같은 행을 읽어 이중 처리된다. 큐에 워커를 여러 대 붙여 수평 확장할 때의 정석이다.
이렇게도 쓴다
집는 즉시 상태를 바꿔 다른 워커 눈에서 치운다. (조합: CTE + UPDATE ... RETURNING)
WITH picked AS (
SELECT id FROM jobs WHERE status='pending'
ORDER BY id FOR UPDATE SKIP LOCKED LIMIT 1
)
UPDATE jobs j SET status='running'
FROM picked WHERE j.id = picked.id
RETURNING j.id, j.payload;
한 건씩 집어 처리하는 단일 워커 루프.
SELECT id FROM jobs WHERE status='pending'
ORDER BY id FOR UPDATE SKIP LOCKED LIMIT 1;
건너뛰지 말고 "잠겨 있으면 바로 에러"로 실패시킨다. (조합: NOWAIT)
SELECT id FROM jobs WHERE id = 5 FOR UPDATE NOWAIT;
-- ERROR: could not obtain lock on row in relation "jobs"
우선순위 큐: 급한 것부터 집는다. (조합: ORDER BY priority)
SELECT id FROM jobs WHERE status='pending'
ORDER BY priority DESC, id FOR UPDATE SKIP LOCKED LIMIT 1;
특정 행만 잠그고 조인 상대는 잠그지 않는다. (조합: OF 테이블명)
SELECT j.id FROM jobs j JOIN users u ON u.id = j.owner_id
WHERE j.status='pending'
FOR UPDATE OF j SKIP LOCKED LIMIT 1;
예약 시각이 된 작업만 골라 집는다. (조합: run_at 필터)
SELECT id FROM jobs WHERE status='pending' AND run_at <= now()
ORDER BY run_at FOR UPDATE SKIP LOCKED LIMIT 1;반응형
'명령어 > DB' 카테고리의 다른 글
| [PostgreSQL] work_mem와 정렬 spill — 큰 ORDER BY가 디스크로 새는 순간 잡아내기 (0) | 2026.07.23 |
|---|---|
| [PostgreSQL] 윈도우 프레임 ROWS/RANGE BETWEEN으로 이동평균·누적합을 낸다 (0) | 2026.07.23 |
| [PostgreSQL] SERIALIZABLE 동시 갱신이 서로를 덮어써 lost update가 날 때 (0) | 2026.07.23 |
| [PostgreSQL] SELECT FOR UPDATE / NOWAIT / FOR SHARE 행을 잠그고 안전하게 갱신한다 (1) | 2026.07.23 |
| [PostgreSQL] 파티셔닝 큰 테이블을 기간별로 쪼개 관리한다 (0) | 2026.07.23 |