현재 테스트 중입니다: 완료되면 GitHub 코드를 오픈할 예정입니다.

예시 세션 (바이트 표기)

정수는 빅엔디안. ··는 바이트 경계 표시일 뿐 실제 바이트는 아닙니다. owner·token은 u64라 8바이트지만, 아래에서는 읽기 쉽게 ⟨owner=7⟩·⟨token=1⟩로 줄여 적습니다.

# 접속 직후 — 인증 핸드셰이크 (연결당 1회)
서버 → "SHA-256 aB3dEf_g" \n
클라 → base64url( SHA-256( token ∥ "aB3dEf_g" ) ) \n     (43자 다이제스트)

# 즉시 획득 (wait=5s, lease=30s), key="order-1234"
클라 → 'A' 05 1E ⟨owner=7⟩ "order-1234" \n
서버 → 'A' ⟨token=1⟩ ⟨owner=7⟩ "order-1234" \n           (owner 에코 — 내 요청의 응답)

# 점유 중 대기 (다른 연결, wait=1s)
클라2 → 'A' 01 1E ⟨owner=9⟩ "order-1234" \n
                                       ... 보류 ...
# (a) 보유자가 반납하면 즉시 인계
클라  → 'R' ⟨token=1⟩ "order-1234" \n                    (받았던 토큰을 실어 보냄)
서버 → 'R' ⟨token=1⟩ "order-1234" \n                     (클라: 반납됨)
서버 → 'A' ⟨token=2⟩ ⟨owner=9⟩ "order-1234" \n           (클라2: 인계, 더 큰 토큰)
# (b) wait(1s) 안에 차례가 오지 않으면
서버 → 'T' ⟨owner=9⟩ "order-1234" \n                     (클라2: 타임아웃 — 발급 없음)

# 응답이 유실된 전송 — 결과 불명
클라 → 'A' 05 1E ⟨owner=7⟩ "order-1234" \n
연결 끊김                                                        (응답 확인 불가 → Indeterminate)
# 같은 owner로 A를 재전송하지 않음. token을 모르는 grant는 lease가 회수

# 대기열이 상한(max_waiters)에 도달했으면
클라3 → 'A' 05 1E ⟨owner=11⟩ "order-1234" \n
서버 → 'B' ⟨owner=11⟩ "order-1234" \n                    (확정 미획득 Busy, 내부 자동 재시도 없음)

# 토큰이 안 맞는 반납 / 없는 키 반납 / 잘못된 요청
클라 → 'R' ⟨token=1⟩ "order-1234" \n  → 서버 'N' ⟨token=1⟩ "order-1234" \n   (이미 token=2가 보유)
클라 → 'R' ⟨token=5⟩ "ghost" \n       → 서버 'N' ⟨token=5⟩ "ghost" \n
클라 → 'Z' ...                        → 서버 'E' "bad_op" \n 후 연결 종료

# 클러스터에서 리더가 아닌 노드에 요청하면
클라 → 'A' 05 1E ⟨owner=13⟩ "order-1234" \n
서버 → 'M' "10.0.0.1:5225" \n                            (힌트 갱신 후 연결 종료; owner가 없어 송신 요청은 Indeterminate)
# 다음 독립 acquire부터 새 leader 연결 사용

# 리더가 바뀌면 서버가 먼저 알려 줌 (요청과 무관한 통지)
서버 → 'L' "10.0.0.2:5225" \n                            (힌트만 갱신 — 연결은 유지)

owner·token 에코가 왜 필요한지는 응답 매칭 규칙에서 다룹니다 — 여러 요청의 응답이 요청 순서와 어긋나 도착할 수 있기 때문에, 클라이언트는 FIFO가 아니라 에코된 식별자로 짝지어야 합니다.

서버 ↔ 서버 사이의 클러스터 합의 프로토콜은 프로토콜 (클러스터)에서 다룹니다.