프로토콜
양방향 동기화에서 충돌 사본이 안 생기는 이유는 폴더마다 쓰는 쪽이 하나이기 때문입니다.
파일 두 개가 전부다. 요청 하나, 응답 하나. 그 위에 규약이 몇 개 얹혀 있다.
폴더마다 쓰는 쪽이 하나다
양방향 동기화는 두 기계가 같은 파일을 고칠 때 충돌 사본을 만든다. 그래서 그 상황이 애초에 안 생기게 폴더를 갈랐다.
| 폴더 | 쓰는 쪽 | 읽는 쪽 |
|---|---|---|
<상대>/inbox |
보내는 사람들 | 상대 |
<상대>/outbox |
상대만 | 보낸 사람들 |
<상대>/log |
상대만 | 누구나 |
어느 파일도 두 기계가 같이 고치지 않는다. 그래서 충돌 해결 로직이 필요 없다 — 충돌이 안 나는 게 아니라 날 수 없는 구조다.
폴더 이름은 실행하는 쪽을 가리킨다. home/inbox는 집 PC가 처리할 것들이다. 처음엔 “보낸 사람 기준”으로 이름을 붙였다가 헷갈려서 뒤집었다 — 파일을 보는 순간 “누가 이걸 실행하나”가 궁금하지 “누가 보냈나”가 궁금한 게 아니었다.
반쯤 쓰인 파일은 복제되지 않는다
파일을 임시 이름으로 다 쓴 뒤 이름을 바꾼다. 동기화 도구가 잡아가는 시점에 이미 완성된 파일이라는 뜻이다.
이걸 안 하면 반쯤 쓰인 JSON이 건너가고, 반대편은 그걸 파싱하다 실패한다. 그리고 그 실패는 재현이 거의 안 된다 — 파일 크기와 동기화 타이밍이 맞아떨어질 때만 나기 때문이다.
식별자가 파일명과 같다
요청 식별자는 항상 파일명과 같고, 그 안에 보낸 사람 이름이 들어 있다.
그래서 두 기계가 같은 inbox에 써도 이름이 부딪히지 않는다. 그리고 파일 목록만 봐도 누가 뭘 언제 보냈는지 읽힌다 — 디렉터리 목록 자체가 로그가 된다.
식별자를 따로 만들고 파일명을 순번으로 두는 방법도 있었는데, 그러면 파일을 열어 봐야 뭐가 뭔지 안다.
침묵과 작업 중을 구분한다
비동기 채널은 에러가 아니라 침묵으로 고장 난다. 그리고 침묵은 “아직 일하는 중”과 구분되지 않는다.
그래서 감시자는 잡을 집는 그 순간에 상태를 running으로 써서 내보낸다. 끝나면 덮어쓴다.
이 한 줄 때문에 “아직 못 봤다”와 “지금 하는 중”이 갈린다. 답이 안 왔을 때 물어볼 질문이 달라진다 — 전자면 동기화를 의심하고, 후자면 그냥 기다리면 된다.
찾은 버그 — head-of-line starvation
한 번에 처리할 개수를 자르는 코드가 이미 답한 요청을 걸러내기 전에 실행되고 있었다.
그래서 처리는 끝났지만 안 치운 요청 3건이 큐 앞에 있으면 새 작업은 영원히 집히지 않는다. 에러 없음. 감시자는 계속 돈다. 로그도 정상이다.
스모크 테스트에서 네 번째 작업이 처리되지 않는 걸로 잡았다. 세 개까지는 전부 통과했으니, 세 개만 던졌으면 못 봤다.
상한이 3이라 네 번째에서 걸린 건데, 이건 운이었다. 상한이 10이었으면 열한 번째에서 걸렸을 테고, 테스트를 열한 개까지 던져 볼 이유가 없다.