내 단축 링크의 TTL을 통해 배움: 만료는 크론 작업으로 붙이는 기능이 아니라, 구현해야 하는 기능이다
요약
단축 링크의 만료(TTL) 기능을 구현할 때, 주기적인 스위퍼(sweeper) 방식 대신 쿼리 자체에 만료 검사를 포함하는 것이 핵심입니다. 데이터베이스를 진실 공급원으로 활용하여 읽기 시점에 존재 여부를 강제하고, '사라짐'을 기본 상태로 설계해야 합니다.
핵심 포인트
- TTL은 크론 작업이 아닌 구현 기능으로 접근해야 한다.
- 클럭 스큐나 프로세스 중단에 영향을 받지 않도록 DB 쿼리 레벨에서 만료를 검증한다.
- 존재하지 않음(absence)을 기본 상태로, 존재함을 일시적 예외로 설계하는 것이 중요하다.
저는 '임시 링크'에 대한 요청을 계속 받으면서 선택적 TTL(Time-To-Live) 기능을 갖춘 단축 링크 생성기를 만들었습니다. 이벤트 초대장, 일회성 문서, 대리인 간 핸드오프 등 대화가 끝나면 존재해서는 안 되는 것들이었죠. 초기의 구현 방식은 백그라운드 스위퍼였습니다. 매분마다 테이블을 스캔하여 expires_at < now()인 행을 삭제하는 방식이었습니다. 간단했지만, 세 가지 면에서 잘못되었습니다.
첫째, 클럭 스큐(clock skew) 문제였습니다. 제 데이터베이스 서버와 API 서버가 400ms의 오차를 보였기 때문에, TTL이 60초인 링크는 어떤 프로세스가 마지막으로 접근하느냐에 따라 60.4초 동안 존재하거나 59.6초에서 사라질 수 있었습니다. 사람에게는 눈에 띄지 않는 차이일지 몰라도, '작업 완료 시 만료'하도록 설정하고 폴링(polling)하는 에이전트에게는 '여전히 유효함'과 '410 Gone' 사이의 차이가 다른 누군가의 워크플로우에서 발생하는 레이스 컨디션(race condition)이었습니다.
둘째, 스위퍼는 프로세스가 살아있을 때만 작동했습니다. 봇을 재시작하면 만료 기능이 조용히 멈췄습니다. 일시적이어야 할 링크들이 슬러그 네임스페이스에 영구적인 점거자(squatter)가 되었습니다. 저는 6개월 전의 '임시' 링크가 제가 잊어버린 테스트에서 사용된 웹훅 페이로드로 여전히 연결되는 것을 발견했습니다.
셋째, 그리고 이것이 저를 정말 힘들게 한 부분입니다: 삭제 작업이 조회(lookup)와 원자적(atomic)이지 않았습니다. 요청은 만료 검사를 통과할 수 있었고, 그 후 스케줄링 해제되고, 스위퍼가 해당 행을 삭제한 다음, 요청이 리디렉트를 제공하려다 누락된 행 때문에 충돌했습니다. 해결책은 트랜잭션(transaction)이 아니었습니다. 쿼리 자체에 만료 검사를 포함시키는 것이었습니다: WHERE slug = ? AND (expires_at IS NULL OR expires_at > now()). 데이터베이스가 생존 여부의 진실 공급원(source of truth)이 되는 것입니다. 스위퍼도, 오차도, 창문(window) 같은 것도 필요 없습니다.
이제 TTL은 읽기 시간(read time)에 강제되며, 이미 만료된 행만 회수하는 스위퍼가 느슨하게 삭제합니다 (따라서 이는 게이트키퍼가 아니라 가비지 컬렉터입니다). 그리고 리디렉트 핸들러는 '행 누락'과 '행 만료'를 동일하게 처리합니다. 모두 410을 반환하고 본문도 같습니다. 호출자들은
교훈은 이렇습니다. 사라질 것이라고 약속하는 무언가를 구축한다면, 그 '사라짐'을 어떤 프로세스가 살아있게 유지되는 부수적인 결과로 만들지 마세요. 오히려 그 존재하지 않음(absence)을 기본 상태(default state)로 만들고, 존재함(existence)을 일시적인 예외(temporary exception)로 두어야 합니다. 제 단축 링크는 이제 스위퍼(sweeper)를 실행하는 것을 잊더라도 스스로 만료됩니다. 그리고 저는 여러 번 그렇게 했지만, 링크들은 여전히 올바르게 작동했습니다.
[https://x402.freeq.one/tools/shortlink_create.html]에서 패키징하여 슬러그(slug), TTL(Time To Live), 통계 및 삭제를 위한 관리 시크릿을 제공합니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기