녹화 파일은 디스크에 있는데 편집기에서는 검색되지 않는다면, 저장은 성공한 걸까요. PokeClip의 편집기는 DB에서 방송 시각에 해당하는 파일을 찾습니다. 녹화 완료 알림을 놓쳐 DB에 등록하지 못한 파일은 사용자에게 없는 파일과 같았습니다.

알림에만 기대지 않고 디스크와 DB를 대조하게 만든 뒤, 정상·알림 유실 네 조건에서 276개 파일을 누락·중복 commit 없이 등록했습니다. 하지만 감시만 남긴 조건의 p95는 0.073초, 최대는 13.526초였습니다. 파일을 모두 찾았다는 결과와 얼마나 늦게 찾았는지는 따로 읽어야 했습니다.

저는 훅을 빠른 처리의 계기로 남기되 복구 기준은 파일과 DB에 두었습니다. 이 경계를 정하고 실패 조건을 골랐으며, 구현과 실험은 AI와 협업했습니다. 왜 빠른 훅만으로는 부족했고 마지막 파일이 어떤 비용을 남겼는지 살펴보겠습니다.

정상 훅은 빨랐지만, 실패를 다시 보내 주지는 않았습니다

초기 대조에서 완료 훅이 읽은 파일 크기는 최종 크기와 29/29 일치했습니다. 알림 지연도 p50 2.6ms, p95 4.9ms였습니다. 그러나 실행 파일이 없거나, 훅이 비정상 종료하거나, 쓰기에 실패한 경우에는 재시도가 없었습니다. 파일 완료 전 강제 종료는 훅 자체를 남기지 않았습니다.

따라서 훅을 더 자주 받는 것만으로 복구를 해결할 수는 없었습니다. 메모리에서 중복을 걸러도 프로세스를 다시 시작하면 그 기록이 사라집니다. 실제 인덱서 구현은 빠른 경로와 다시 찾는 경로를 함께 둡니다.

경로 맡은 일 놓칠 수 있는 부분
완료 훅 완성 파일을 즉시 알림 실행 실패와 강제 종료
파일 감시 생성·변경된 파일을 재발견 마지막 파일은 유휴 판정 대기
주기 재스캔 디스크와 DB를 대조 스캔 주기만큼의 복구 지연
DB 확정 위치·순서·길이와 중복 여부 확정 파일 중복과 순번 충돌을 구분해야 함

세 경로가 같은 파일을 발견할 수 있으므로, 순번과 방송 위치는 한 작성자가 확정하고 재발견에 따른 중복 등록은 DB 고유 제약으로 막았습니다. 인덱서는 읽기 전용으로 붙인 원본에서 fMP4 내부 길이를 읽습니다. 파일명이나 벽시계 차이로 길이를 추측하지도, 복구 과정에서 원본을 고치지도 않습니다.

이 구조에서 남은 질문은 “지금 읽어도 완성된 파일인가”였습니다. 크기가 잠깐 멈춘 순간은 파트 쓰기 사이의 공백일 수 있습니다. 후속 파일, 유휴 종료, 과거 파일 스캔, 꼬리 재성장을 나눠 판정한 이유입니다. 이 판정의 차이는 뒤의 감시 단독 시험에서 마지막 파일의 지연으로 나타났습니다.

실제 등록 경로를 끊어 본 네 가지 조건

2026년 10월 6일에는 스캔 함수만 호출하지 않고 main 타이머 → StartCollect → ApplyCollect → PostgreSQL commit 경로를 실행했습니다. Apple M5, Go 1.26.5, PostgreSQL 17에서 완료된 fixture 파일을 50ms 간격으로 주입했고, mtime은 60초 전으로 설정했습니다.

조건 파일 수 등록 지연 p95 최대 누락 / 중복 commit
훅 + 파일 감시 90 0.067초 0.123초 0 / 0
훅 없음, 감시만 90 0.073초 13.526초 0 / 0
둘 다 없음, 5초 재스캔 90 4.973초 5.019초 0 / 0
둘 다 없음, 기본 300초 재스캔 6 300.014초 300.024초 0 / 0

앞의 세 조건은 각 3회, 기본 300초 조건은 1회입니다. 합계 276파일, 누락 0, 중복 commit 0입니다. 측정 조건과 원시 결과 요약에서 5초는 가속 시험이고 제품 기본값은 300초입니다. 따라서 5초 안에 돌아온 결과만으로 제품의 복구 시간을 설명할 수는 없습니다.

감시만 둔 조건은 p95가 0.073초인데 최대는 13.526초였습니다. 대부분의 파일은 후속 파일 덕분에 빨리 완성을 판정하지만, 각 실행의 마지막 파일은 유휴 상태를 기다립니다. 평균적인 발견 속도만 보면 이 꼬리가 가려집니다. 두 신호가 모두 없으면 재스캔 간격이 복구 시간을 지배했습니다.

파일을 찾는 것과 재접속 경계를 찾는 것은 다릅니다

파일을 회수했다고 방송의 모든 사건을 복원한 것은 아닙니다. 짧은 재접속 대조에서는 훅 ON의 DB 시간차가 574ms, OFF가 583ms로 모두 기존 1.5초 기준 아래였습니다. ON에서만 다음 조각 seq 5에 불연속 표식이 남았고, 준비된 사건 1건과 소비된 사건 1건이 대응했습니다. 서버의 offline→online 공백 0.886초는 DB 시간차와 별도 지표입니다. 이 변경은 PR #33에 있습니다.

정상 120초 송출은 30파일=30행이었고, 훅을 끈 롤백도 10파일=10행으로 수집을 유지했습니다. 다만 연결 사건 자체를 놓치면 짧은 재접속 표식까지 복원된다고 약속할 수는 없습니다.

복구 주기를 줄이기 전에 남은 비용

이번 시험은 완료 fixture를 넣고 알림 채널을 제공하지 않은 결함 주입입니다. 실제 OS 알림 장애·방송·S3 업로드·커서 이전 구멍 복구·디렉터리 규모별 스캔 비용은 포함하지 않았습니다. 276파일의 등록 결과는 이 범위의 근거이며 운영 복구 SLO는 아직 정하지 않았습니다.

알림이 둘 다 없을 때 기본 재스캔의 최대 지연은 300.024초였습니다. 이를 줄이려면 스캔을 더 자주 해야 하고, 그만큼 디렉터리 탐색 비용을 확인해야 합니다. 반면 마지막 파일만 늦는 문제는 유휴 판정에서 나옵니다. 저는 두 지연을 같은 “인덱서가 느리다”로 묶지 않았습니다. 빠른 알림은 유지하고, 남은 파일을 다시 등록할 경로와 그 경로의 대기 시간을 각각 관리하는 구조로 정리했습니다.


이 글은 PokeClip의 개발·검증 기록을 2026년 10월 15일 기준으로 정리한 CASE 15입니다. 전체 기술 기록에서 연결되는 결정을 함께 읽을 수 있습니다.

직접 바꿔보기 · 설명용 모형

이벤트가 없어도 인덱스를 채울 수 있을까?

아래 결과는 선택한 입력으로 계산합니다. 실제 서버에 요청하거나 본문의 실험을 재실행하지 않습니다.

디스크에는 8개 파일이 있고, DB에는 처음 4개만 등록되어 있다고 가정합니다. 이벤트를 놓친 뒤 재조정 작업을 실행해 보세요. 입력을 바꾸면 처음 상태로 돌아갑니다.

디스크
1 · 2 · 3 · 4 · 5 · 6 · 7 · 8
DB 인덱스
1 · 2 · 3 · 4

DB에 없는 파일을 디스크에서 찾아 등록합니다. 같은 목록을 다시 처리해도 중복 등록하지 않습니다.

이 모형은 식별자 집합만 비교합니다. 디스크에서 사라진 영상 바이트를 복원하지 않으며, 동시성·DB 트랜잭션·실제 파일명의 규칙은 생략했습니다.