기술

배포 확인 표시는 늘 최신이었는데, 서버는 옛 모듈을 들고 있었습니다

2026.10.067분 읽기

자사 영상 콘텐츠 프로젝트의 제작 도구를 만들고 있습니다. 로컬에서 서버가 하나 뜨고, 웹 화면이 그 서버를 부르고, 실제 제작 단계는 플러그인 쪽 스크립트가 맡는 구조입니다. 첫 편을 실제로 만들면서 자막 나누기 규칙을 고쳤습니다.

고치고 다시 돌렸는데 화면에 나오는 자막이 그대로였습니다. 코드를 다시 열어 봐도 수정은 분명히 들어가 있었습니다. 화면 구석에 띄워 둔 배포 확인 값도 최신이었습니다. 코드도 맞고 배포 표시도 최신이니 의심할 것이 하나도 남지 않았습니다. 여기서부터가 진짜로 헤맨 구간입니다.


최신이라고 답한 값은 다른 질문에 답하고 있었습니다

그 값이 무엇을 읽는지 열어 봤습니다. 요청이 올 때마다 저장소를 새로 읽어서 지금 저장소의 상태를 답하고 있었습니다. 파일을 고친 순간 저장소는 이미 새것이니, 그 값은 **언제 봐도 최신**입니다.

제가 묻던 것은 그것이 아니었습니다. 저는 '지금 도는 코드가 새것인가'를 묻고 있었고, 화면은 '저장소가 새것인가'에 답하고 있었습니다. 두 질문은 같은 화면 구석에 나란히 놓여 있었기 때문에 같은 것을 말한다고 믿었습니다.

자막과 미디어 계산을 맡는 모듈은 부수효과가 없는 순수 모듈이라 서버 프로세스가 뜰 때 한 번 올라옵니다. 파일을 고쳐도 이미 떠 있는 프로세스는 기동 때 올린 옛것을 계속 들고 있습니다. 코드도 맞고 표시도 최신인데 결과만 옛것이었던 이유가 그것입니다.

배포 확인 값은 저장소를 읽고 개발자의 질문은 프로세스를 향해, 두 질문이 어긋나는 구조를 보여주는 그림


한 저장소 안에서도 반영 시점이 갈립니다

파고 보니 같은 저장소 안에서 반영 시점이 두 갈래였습니다. 순수 모듈은 프로세스가 뜰 때 한 번 올라와 그대로 굳고, 제작 단계 스크립트는 자식 프로세스로 매번 새로 실행돼 고치는 즉시 반영됩니다. 커밋 하나로 배포 상태를 답하려 들면 이 둘을 구분할 말이 없습니다.

무엇이

언제 반영되나

고친 뒤 필요한 것

기동 때 올라오는 순수 모듈

프로세스가 뜰 때 한 번

서버 재기동

요청마다 다시 읽는 값

요청이 올 때마다

없음

자식 프로세스로 도는 스크립트

실행될 때마다

없음

배포 상태를 하나의 값으로 답하려 들면 반드시 이 중 어느 한 갈래를 틀리게 말합니다. 위 표의 첫째 줄(기동 때 올라오는 순수 모듈)만 재기동이 필요한데, 커밋 값은 세 줄을 구분하지 않습니다.

한 저장소 안에서 기동 적재·요청마다 읽기·자식 프로세스 세 갈래로 반영 시점이 갈리는 구조도


커밋으로 물을 것인가 파일로 물을 것인가

다시 띄우라는 안내를 어느 기준으로 낼지에서 갈림길이 하나 더 있었습니다.

커밋 기준 — 한 줄이면 됩니다. 대신 고치는 즉시 반영되는 자리까지 싸잡아 다시 띄우라고 합니다. 안 그래도 되는데 자꾸 뜨는 안내는 사람이 곧 무시합니다

파일 지문 기준 — 프로세스에 실제로 올라간 파일만 봅니다. 즉시 반영되는 자리는 조용하고, 정말 옛것을 들고 있을 때만 뜹니다

파일 지문 기준으로 갔습니다. 모듈이 올라오는 순간 그 파일들의 지문을 떠서 프로세스 안에 적어 두고, 요청이 올 때마다 지금 디스크에 있는 파일의 지문과 견줍니다. 다르면 화면 오른쪽 위에 '서버를 다시 띄우세요'가 뜹니다.

바뀐 것은 기능이 아니라, 실행 중인 파일이 최신인지 확인하는 방식입니다. 이제 '고쳤는데 왜 그대로지'를 사람이 머리로 추적하지 않고, 화면이 먼저 말합니다. 자막 나누기 수정 자체는 66장면 전부에서 걸리는 것 0건으로 확인했고, 그날 검증은 플러그인 265개·서버 137개·웹 225개 테스트 통과로 닫았습니다.

같은 축의 앞선 실패가 하나 더 있습니다. 배포 관문이 182ms 만에 통과 판정을 냈는데, 그 관문이 본 것은 아직 살아 있던 옛 프로세스의 헬스체크였습니다. 관문이 무엇을 보고 있는지가 그때도 논점이었습니다.

고친 뒤 결과가 그대로일 때 사람이 추적하던 흐름과 화면이 먼저 알려주는 흐름을 전후로 비교한 그림


반대 방향으로도 같은 날 한 번 데었습니다

자동 재시작 옵션을 켜 두면 이 문제 자체가 안 납니다. 다만 값이 공짜는 아닙니다. 같은 날 자동 재시작으로 띄운 개발 서버의 코드를 고쳤다가, 돌고 있던 유료 작업 두 건이 재시작에 같이 멈췄습니다. 각각 21초와 1분 36초 지점이었고, 기록에는 사유가 '서버 종료'로 남았습니다.

그래서 고치기 전에 진행 중인 작업 목록을 먼저 본다는 규칙을 메모로 남겼습니다. 오래 도는 작업을 안고 있는 서버에서는 자동 재시작이 더 비쌉니다. 한쪽을 끄면 다른 쪽이 비용을 냅니다.


확인 장치를 만들 때 먼저 답할 것

이번 일에서 남은 것은 자막 규칙이 아니라 확인 장치를 세우는 순서입니다. 아래 네 가지를 만들기 전에 답해 두면 같은 자리에서 다시 헤매지 않습니다.

이 표시가 틀렸다면 화면에 무엇이 보이나. 답이 '똑같이 보인다'면 그 장치는 아무것도 확인하지 않습니다. 항상 최신이라고 답하는 표시만으로는 옛 코드가 실행 중인 상태를 찾을 수 없습니다

그 값이 무엇을 읽어서 최신인가. 값이 최신이라는 사실보다 읽는 대상이 내 질문과 짝이 맞는지가 먼저입니다

반영 시점이 몇 갈래인가. 기동 때 굳는 것, 요청마다 새로 읽는 것, 자식 프로세스로 매번 도는 것을 한 값으로 답하려 들지 않습니다

원천이 다른 값을 같은 화면 구석에 나란히 두지 않는다. 사람은 나란히 있는 두 값을 하나로 읽습니다

확인이 확인이 아니었던 사례는 이번이 처음이 아닙니다. 하루에 배포 확인을 세 번 했는데 셋 다 실패할 수 없는 검사였던 날이 있었습니다. 검사를 고르는 기준을 그때 정리해 뒀습니다.


이 이야기가 닿는 자리와 닿지 않는 자리

운영 환경은 대개 배포 단위와 프로세스 수명이 같습니다. 새로 배포하면 프로세스도 새로 뜨니 커밋 표시로 충분한 경우가 많습니다. 이 이야기는 개발 서버처럼 프로세스가 오래 살아 있는 자리의 것입니다.

파일 지문 대조도 만능은 아닙니다. 우리 파일만 보기 때문에 의존 라이브러리가 바뀐 것이나 환경변수가 바뀐 것은 못 잡습니다. 지문 대조 역시 무엇을 묻고 있는지를 좁혀 놓은 검사일 뿐입니다.

확인 장치가 늘 같은 답을 낸다면, 그 장치는 확인을 하는 것이 아니라 확인했다는 기분을 주고 있는 것입니다. 배포 표시를 하나 붙이기 전에 그 표시가 틀렸을 때 무엇이 달라 보이는지부터 적어 두면, 나중에 잃는 시간이 줄어듭니다.

#배포확인#핫리로드#프로세스수명#관측설계#개발서버#디버깅