31장. PostgreSQL transaction으로 한 번만 배정한다
두 worker가 DH-1842를 동시에 읽는 실습에서 둘 다 후보를 찾을 수 있다. 확정은 transaction 안에서 request row를 FOR UPDATE로 잠그거나 where status='MATCHING' 조건부 update를 수행한다. assignment의 request id unique와 technician active constraint를 DB에 둔다. application check만으로 경쟁을 막지 않는다.
transaction callback 안에서 지도 API를 호출하지 않는다. 후보 거리와 정책 input은 미리 얻되 확정 직전 version과 availability를 다시 확인한다. DB connection을 외부 timeout 동안 잡지 않는다. deadlock은 lock 순서를 통일하고 실패한 transaction 전체를 제한적으로 retry한다.
통합 test는 실제 PostgreSQL에서 두 Promise를 barrier 뒤 동시에 시작한다. 성공 assignment 1건, lost-race 1건, status event 1건, outbox 1건을 대사한다. test가 가끔 통과하는 것으로 끝내지 않고 반복 실행과 DB constraint error mapping을 확인한다.
update dispatch_request
set status = 'ASSIGNED', technician_id = $2, version = version + 1
where id = $1 and status = 'MATCHING' and version = $3
returning id, status, technician_id, version;