한 제공자의 새로고침이 다른 제공자의 캐시를 신선하게 보이게 만들지 마세요
요약
캐시 시스템 설계 시 여러 데이터 제공자(provider)의 신선도를 개별적으로 관리해야 함을 강조합니다. 하나의 타임스탬프로 전체 스냅샷을 갱신할 경우, 실패한 제공자의 오래된 데이터가 신선한 데이터로 오인되는 문제를 방지하는 설계 패턴을 제안합니다.
핵심 포인트
- 제공자별로 독립적인 신선도 타임스탬프를 모델링하여 데이터 신뢰성을 확보해야 함
- 에러 응답이나 빈 응답을 신선한 데이터로 간주하여 캐싱하는 것을 금지해야 함
- 부분적 성공 시 기존 값을 보존할 수는 있으나, 타임스탬프는 각 제공자의 실제 업데이트 시점을 반영해야 함
- 스냅샷 전체의 타임스탬프가 개별 데이터의 유효성을 보증하는 수단이 되어서는 안 됨
데스크톱 사용 뷰(usage view)는 콜드 스타트(cold starts)와 일시적인 네트워크 장애에 대비해 캐시가 필요합니다. 위험한 지름길은 전체 스냅샷(snapshot)에 하나의 신선도 타임스탬프(freshness timestamp)를 부여하는 것입니다.
만약 Claude는 성공적으로 새로고침되었으나 Codex가 실패했을 때, 새로운 타임스탬프와 함께 공유 캐시를 다시 쓰게 되면 오래된 Codex 데이터의 수명이 조용히 연장될 수 있습니다. 값 자체는 여전히 다르지만, 그 신뢰 경계(trust boundary)가 무너진 것입니다.
해결책은 실패가 발생하는 지점, 즉 제공자(provider)별로 신선도를 모델링하는 것입니다.
값과 그 유효 기간을 함께 저장하세요
Agent Island v1.7.1은 Claude 데이터, Codex 데이터, 호환성 타임스탬프(compatibility timestamp), 그리고 별도의 제공자 타임스탬프(provider timestamps)를 저장합니다:
snapshot = {
claude,
codex,
...
전체 타임스탬프는 오래된 레코드를 디코딩하거나 명백히 오래된 스냅샷을 거부하는 데 여전히 유용합니다. 하지만 이것이 두 제공자 값을 모두 복구하도록 승인하는 것은 아닙니다.
이는 중요한 차이점입니다. 공유 파일은 구현 세부 사항(implementation detail)일 뿐이며, 공유된 신선도 보증(freshness guarantee)이 아닙니다.
빈 응답과 에러 응답은 신선한 사용 데이터가 아닙니다
제공자 결과는 관련 윈도우(windows)에 에러가 없고, 최소 하나 이상의 실제 신호(real signal), 즉 양수 퍼센트(positive percentage) 또는 리셋 타임스탬프(reset timestamp)가 존재할 때만 캐싱 가능해야 합니다.
두 개의 0% 윈도우를 가진 플랜 레이블(plan label)만으로는 충분하지 않습니다. 인증 실패(Authentication failures)와 빈 응답(empty responses)은 종종 깨끗해 보이는 형태를 만들어냅니다. 이러한 형태를 캐싱하는 것은 증거의 부재를 확신에 찬 0%로 바꾸는 결과를 초래합니다.
에러를 포함하는 값은 이전의 성공적인 페치(fetch)에서 가져온 퍼센트를 포함하고 있더라도 안전하지 않습니다. 해당 퍼센트가 현재 화면에는 유용할 수 있지만, 새로운 시간과 함께 저장하면 오래된 데이터가 신선한 캐시 항목으로 세탁(launders)됩니다.
부분적 성공은 보존할 수는 있지만, 갱신할 수는 없습니다
Claude는 성공하고 Codex는 타임아웃(timeout)되는 새로고침 상황을 가정해 봅시다. 스냅샷은 마지막으로 유효했던 Codex 값을 그대로 유지하면서 Claude의 새로운 값을 저장할 수 있습니다. 이때 타임스탬프는 진실을 말해야 합니다:
claude value: new claudeUpdatedAt: now
codex value: preserved codexUpdatedAt: old timestamp
두 제공자 모두 캐시 가능한 신선한 데이터를 생성하지 않았다면, 새로운 스냅샷을 작성하지 마십시오. 반복되는 실패가 캐시를 무기한 연장하게 해서는 안 됩니다.
데이터를 가져오지 않은(unfetched) 제공자도 동일한 규칙을 따릅니다. 해당 제공자는 이전에 유효했던 값을 유지할 수는 있지만, 단지 피어(peer)가 페치(fetch)되었다는 이유만으로 새로운 타임스탬프를 받아서는 안 됩니다.
제공자를 독립적으로 복구하기
복구(restore) 과정에서 각 제공자의 타임스탬프를 최대 허용 기간(maximum age)과 비교하십시오. Claude는 복구되는 동안 Codex가 만료될 수 있으며, 그 반대의 경우도 발생할 수 있습니다.
이러한 동작은 스냅샷 전체를 거부하는 것보다 더 정직하고 유용합니다. 부분적인 장애가 발생하더라도, 두 제공자를 동일한 신뢰도로 제시하지 않으면서 하나의 검증된 제공자만 보여줄 수 있습니다.
스키마 진화(Schema evolution)에도 동일한 주의가 필요합니다. 제공자의 응답에는 하나의 의미 있는 사용 기간(usage window)이 포함될 수 있고, 다른 하나는 명시적으로 생략될 수 있습니다. 실제 사용 기간에 사용량이나 리셋 증거가 포함되어 있다면 해당 데이터는 캐시 가능(cacheable)한 상태로 유지됩니다. 두 개의 기간이 모두 완전히 채워져 있을 것을 요구한다면, 유효한 응답조차 영구적인 캐시 미스(cache miss)로 변질될 것입니다.
타임스탬프 세탁을 잡아내는 테스트
유용한 정책 테스트 스위트(test suite)는 다음 사항을 증명해야 합니다:
- 오류를 포함하는 보존된 사용량(preserved usage)은 스냅샷을 생성하거나 갱신할 수 없다.
- 플랜 정보만 있는 0% 데이터는 건강한 사용량으로 복구될 수 없다.
- 캐시 오류가 제거되는 동안에도 실제 사용량은 그 비율과 리셋 시간을 유지한다.
- 신선한 Claude 데이터는 Codex의 타임스탬프를 변경하지 않고 오래된 Codex 데이터를 보존할 수 있다.
- 데이터를 가져오지 않은(unfetched) 제공자는 절대 새로운 타임스탬프를 받지 않는다.
- 복구 시 한 제공자는 유지하고 다른 제공자는 만료시킬 수 있다.
- 유효한 단일 기간(single-window) 응답은 캐시 가능한 상태로 유지된다.
측정 경계를 명확하게 유지하기
캐시의 정확성은 사용량 표시의 정직함을 향상시킵니다. 이는 지표(metric)가 의미하는 바를 바꾸지는 않습니다.
사용량 비율과 로컬 API 값 추정치는 구독 청구서, 절감액, 매출, 사용자 수 또는 설치 수가 아닙니다. 기술적으로 정확한 캐시는 근거가 되는 소스(source)가 지원하는 것보다 더 강력한 비즈니스 주장을 하는 데 사용되어서는 안 됩니다.
재사용 가능한 규칙은 간단합니다:
신선도(freshness)의 범위를 실패한 의존성(dependency)으로 한정하십시오. 직접 가져오지 않은 데이터를 절대 갱신하지 마십시오. 그리고 빈 응답(empty response)을 0%로 전환하기 전에는 반드시 증거를 요구하십시오.
전체 정책, 호환성 동작(compatibility behavior) 및 제품 경계(product boundary)는 canonical engineering article에서 확인할 수 있습니다. Agent Island v1.7.1 소스는 MIT 라이선스 하에 공개되어 있습니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기