0 API障害時に「存在しない」をキャッシュしない:暗号資産メタデータのnegative cache設計メモ #Web3 #市場データ #キャッシュ #可観測性 #障害設計 みんなに公開
APIが404、空配列、タイムアウトのいずれかを返したとき、それらを同じ「存在しない」として保存すると、障害中の一時的な欠落が長時間残る。暗号資産メタデータでは、チェーンの遅延、インデクサの再同期、レート制限、フェイルオーバー直後などでも同じ症状が出るため、absence は事実ではなく観測結果として扱う。
四つの状態
| 状態 | 意味 | UIでの扱い |
|---|---|---|
| PRESENT | 現在の応答で存在を確認できた | 通常表示 |
| CONFIRMED_ABSENT | 権威ある条件で不存在を確認できた | 「未登録」など根拠付きで表示 |
| STALE_PRESENT | 過去に確認した値はあるが再検証に失敗した | 最終確認時刻とともに古い値を表示 |
| UNKNOWN | 不在も存在も確認できない | 「取得できません」と表示し、再試行可能にする |
404 や空配列だけで CONFIRMED_ABSENT に遷移させない。まず応答元、チェーン、ブロック高、インデクサの同期状態、エラー種別を確認する。確認条件を満たさない場合は UNKNOWN、既知の値が残っていれば STALE_PRESENT とする。
キャッシュキーとTTL
キーは少なくとも (chain_id, normalized_asset_id, schema_version, source_class) で分離する。大文字小文字、mint と contract、native asset と wrapped asset を同じキーに混ぜない。
- PRESENT: 通常TTL。更新頻度に合わせる。
- CONFIRMED_ABSENT: 短いTTL。判定根拠と確認時刻を必ず保存する。
- STALE_PRESENT: stale-while-revalidate 用の上限を持たせる。
- UNKNOWN: negative cache に書かない。短いジッター付き再試行だけを予約する。
判定フロー
- 権威あるソースから有効なメタデータを取得できたら PRESENT。
- 応答が失敗しても、最後に確認した値があれば STALE_PRESENT。
- 不存在を確認するための独立した条件をすべて満たした場合だけ CONFIRMED_ABSENT。
- それ以外は UNKNOWN とし、「空のメタデータ」を永続化しない。
フェイルオーバー先の空応答で、正常系キャッシュを上書きしてはいけない。更新は observed_at と source_revision を比較し、古い観測が新しい状態を巻き戻さないよう条件付きで行う。
UI契約
UIは値だけでなく状態、観測時刻、出典、再試行可能性を受け取る。UNKNOWN を「トークンが存在しない」と翻訳せず、STALE_PRESENT では古い可能性を明示する。これにより、障害が事実のように見える問題を避けられる。
観測する指標
- metadata_state_total{state,source}
- negative_cache_write_total{reason}
- stale_value_age_seconds
- upstream_error_total{source,class}
- state_transition_total{from,to}
UNKNOWN -> CONFIRMED_ABSENT が急増した場合は、データ品質の改善ではなく判定条件の破損を疑う。
最低限のテスト
- 一時的な500とタイムアウトが negative cache を作らない。
- フェイルオーバー先の空配列が既知の値を消さない。
- 同期遅延中は UNKNOWN または STALE_PRESENT になる。
- 権威ある不存在だけが CONFIRMED_ABSENT になる。
- TTL満了後に再検証される。
- 古い応答が新しい PRESENT を上書きしない。
私はエレバンでARMCPのFounder & CEOとして、市場データと障害時UXの境界を設計している。このメモは投資助言ではなく、実装時の失敗条件を明確にするための技術ノートである。関連情報: https://armcp.net/
AI支援で初稿と構成を作成し、Mushegh Manukyanが技術内容を確認・修正して採用しました。
コメント(0)