サーバーサイドキャッシュは昔から機能していた - 同じ date/time/lat/lon の決定的なチャート計算は、再計算されずにキャッシュから返される。しかし クライアントはこれを見えていなかった。ダッシュボードの「cache hit %」列は – と表示されていた。なぜならバックエンドは cache-outcome を内部メトリクスに記録していたが、レスポンスには含めていなかったからだ。
今では各レスポンスに次の3つのヘッダーのうちいずれかが含まれる:
X-Cache: HIT # обслужено з кешуX-Cache: MISS # обчислено з нуля, результат збереженоX-Cache: BYPASS # не кешується за дизайномこれは小さな変更 - ヘッダーと api_request_log の1つのカラムを追加しただけだが、これにより以前は盲点だった最適化の一クラスが開かれる。
curl -I -X POST https://api.astroway.info/v1/chart \ -H "X-Api-Key: aw_live_..." \ -H "Content-Type: application/json" \ -d '{ "date": "1990-05-15", "time": "14:30:00", "timezoneOffset": 3, "latitude": 50.45, "longitude": 30.52 }' | grep -i x-cache# X-Cache: MISS同じリクエストボディで2回実行してみて:
# X-Cache: HIT/v1/transits/now タイプのエンドポイント(動的時間)では、X-Cache: BYPASS となる。なぜなら結果は現在の Date.now() に依存しており、キャッシュしても意味がないからだ。
どのエンドポイントが返すか
Section titled “どのエンドポイントが返すか”すべてのエンドポイントがキャッシュされるわけではない - これは意図的だ。内訳:
- 決定的チャート計算 (
/v1/chart,/v1/houses,/v1/aspects,/v1/synastry,/v1/dasha/*,/v1/vargas/*) - 完全にキャッシュされる。期待されるパターンは MISS → HIT。 - 時間依存 (
/v1/transits/now,/v1/horoscope/today,/v1/moon/phase-now) -BYPASS。キャッシュはせいぜい1分間しか正しくないため、そもそもキャッシュしないほうが簡単だ。 - AI生成コンテンツ (
/v1/horoscope/personal,/v1/interpret/*) -BYPASS。LLMの回答は同じプロンプトでも決定的ではないため、キャッシュするとランダム性を固定してしまう。 - レンダーエンドポイント (
/v1/render/*) - 一部はMISS/HIT、大きなペイロード(たとえば500点の eclipse-path)を受け取るものはBYPASS。
特定のエンドポイントのマーカーはレスポンスからすぐにわかる - ドキュメントを読まずともキャッシュされるかどうかがわかる。
Pricing impact: キャッシュされたリクエストも 同じく コストがかかる
Section titled “Pricing impact: キャッシュされたリクエストも 同じく コストがかかる”これが理解する上で最も重要な点 - キャッシュされたリクエストも MISS と同じティアで credits を引き続き消費する。理由:
- 私たちの価格設定は CPU コストではなくエンドポイントのビジネス価値に基づいて校正されている。
/v1/chartはチャートを再計算してもキャッシュから返しても同じコストで、クライアントは同じチャートを得る。 - 透明性。あるユーザーベースが MISS に対して支払い、別のユーザーベースが HIT に対して支払う状況(理論的には「キャッシュの運」による)は避けたい。価格は予測可能であるべきだ。
- キャッシュインフラは付加価値ではなくインフラであり、私たちはそれをティア内で補填している。
しかしこれは X-Cache が価格文脈で意味がないということではない - これはクライアントに対して アーキテクチャの可能性 を示している(次のセクション参照)。
クライアント側でどうするか
Section titled “クライアント側でどうするか”4つの実践的なパターン:
1. MISS 用のクライアントサイドキャッシュレイヤー
Section titled “1. MISS 用のクライアントサイドキャッシュレイヤー”X-Cache: MISS が表示されるリクエストで、シナリオによって繰り返される可能性がある(同じ人物のネイタルチャートなど)場合は、Redis/Memcached/IndexedDB にローカルでキャッシュせよ。サーバーサイドキャッシュは TTL と evict ポリシーを持っている - コントロール可能な TTL を持つクライアントサイドレイヤーなら、不要な credit-deduct を避けられる。
import { Astroway } from "@astroway/sdk";
const cache = new Redis();const client = new Astroway({ apiKey: process.env.ASTROWAY_KEY, // optional: hook on response headers onResponse(req, res) { const cacheStatus = res.headers["x-cache"]; metrics.increment(`astroway.cache.${cacheStatus.toLowerCase()}`); },});
async function getChart(input: ChartInput) { const cacheKey = `chart:${hashChart(input)}`; const cached = await cache.get(cacheKey); if (cached) return JSON.parse(cached);
const chart = await client.chart.create(input); await cache.set(cacheKey, JSON.stringify(chart), "EX", 86400); return chart;}2. バックエンドでのバッチ+デデュプ
Section titled “2. バックエンドでのバッチ+デデュプ”あなたのサービスが同じ birth-data に対する大量のリクエストを受け取る場合(オンボーディングキャンペーンで同僚が同じデモデータをテストしているなど)、プロミスベースのデデュプを使え:
const inFlight = new Map<string, Promise<Chart>>();
function getChart(input: ChartInput) { const key = hashChart(input); if (inFlight.has(key)) return inFlight.get(key)!;
const promise = client.chart.create(input); inFlight.set(key, promise); promise.finally(() => inFlight.delete(key)); return promise;}これはクレジットを節約しない(各呼び出しは依然としてカウントされる)が、同時アクセスのスパイクによるボトルネックを解消する。
3. クリティカルパスのプリウォーム
Section titled “3. クリティカルパスのプリウォーム”製品に rituel チャート(人気のデイリー占星術サインなど)がある場合は、スケジュールされた cron でプリウォームせよ。その日の最初の呼び出しは MISS、evict までのその後の呼び出しはすべて HIT。ユーザーはサブセカンドのレスポンスを得る。
4. ダッシュボードインサイト: どこで過剰支払いしているか
Section titled “4. ダッシュボードインサイト: どこで過剰支払いしているか”/dashboard/usage のエンドポイントごとの新しい「cache hit %」列は次のように示す:
- HIT% = 90+ - エンドポイントはよくキャッシュされており、おそらく同じチャートが複数回送信されている。クライアントサイドデデュプ(#2)を検討せよ。
- HIT% = 0 かつ BYPASS: エンドポイントは設計上キャッシュされない(transits/now, AI など)。これは正常だ。
- HIT% = 50% かつ MISS: リクエストの半分は一意のパラメータ、残り半分は繰り返し。クライアントサイドキャッシュは価値がある。
- HIT% が低い + エンドポイントが決定的: 疑わしい。クライアントがペイロードにランダムなフィールド(タイムスタンプや request-id など)を追加してキャッシュキーを汚していないか確認せよ。
技術的実装: 興味がある人向け
Section titled “技術的実装: 興味がある人向け”トラッキングは api_request_log.cache_status という1つのカラムを追加するだけ(enum: MISS|HIT|BYPASS、マイグレーション 030)。このカラムはキャッシュルックアップの決定を行う同じハンドラーから設定されるため、DB への追加クエリは行われない。
GET /v1/me/usage/endpoints は теперь、あなたの履歴の各エンドポイントに対して null ではなく実際の cache_hit_pct を返す。SDK メソッド client.me.usage.endpoints() はこのフィールドを自動的に取得する(型は次の codegen リリースで提供される)。
キャッシュインストルメンテーションは「no caching」と「full edge cache」の間の中間最適化レベルを開く。ロードマップの次の手順:
Cache-Controlレスポンスヘッダーにキャッシュされたエンドポイントの実際の TTL を含める - クライアント側の CDN/proxy キャッシュを可能にする。If-None-MatchETags: レスポンスにフルペイロードを含めずに MISS の再チェックを行う。- ダッシュボードでの per-user キャッシュ統計、無効化のオプション付き(例: birth-time の修正後に特定のチャートを強制的に再計算)。
ドキュメント - /ドキュメント/api/ → パフォーマンス & キャッシング。X-Cache の具体的なリファレンスは各エンドポイントのヘッダー セクションにある。
Solar Fireと同じSwiss Ephemeris - 4行のコードで。
無料のキー(カード不要)。最初の支払いまでに月5,000回の呼び出し。