La caché del lado del servidor funcionaba desde hace tiempo: el cálculo determinista de una carta para la misma date/time/lat/lon se devuelve desde la caché, en lugar de recalcularse. Pero el cliente no lo veía. En el dashboard, la columna “cache hit %” mostraba – porque el backend registraba el cache-outcome en una métrica interna y no en la respuesta.
Тепер кожна response несе один з трьох заголовків:
X-Cache: HIT # обслужено з кешуX-Cache: MISS # обчислено з нуля, результат збереженоX-Cache: BYPASS # не кешується за дизайномЦе маленька зміна - заголовок плюс одна колонка в api_request_log - але вона відкриває цілий клас оптимізацій, які раніше були сліпою плямою.
Как funciona: пример
Sección titulada «Как funciona: пример»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Виконати другий раз з тим самим тілом запиту:
# X-Cache: HITДля ендпоінтів типу /v1/transits/now (динамічний час) - X-Cache: BYPASS, бо результат залежить від поточного Date.now() і кешувати немає сенсу.
Qué endpoints devuelven
Sección titulada «Qué endpoints devuelven»Не всі ендпоінти кешуються - і це навмисно. Розбивка:
- Cálculos de carta determinados (
/v1/chart,/v1/houses,/v1/aspects,/v1/synastry,/v1/dasha/*,/v1/vargas/*) - кешуються повністю. Очікувано MISS → HIT pattern. - Time-dependent (
/v1/transits/now,/v1/horoscope/today,/v1/moon/phase-now) -BYPASS. Кеш би міг бути правильним лише до кінця хвилини, тому простіше не кешувати взагалі. - AI-generated content (
/v1/horoscope/personal,/v1/interpret/*):BYPASS. LLM-відповіді не детерміновані навіть на однаковий промпт, кешувати = фіксувати випадковість. - Render endpoints (
/v1/render/*):MISS/HITдля деяких,BYPASSдля тих, що приймають великі payload-и (eclipse-path з 500 точками).
Маркер на конкретний endpoint видно зразу з response - не треба читати документацію щоб зрозуміти кешується чи ні.
Impacto en precios: las solicitudes cacheadas igualmente cuestan
Sección titulada «Impacto en precios: las solicitudes cacheadas igualmente cuestan»Це найважливіша річ для розуміння - кешовані запити продовжують deduct credits на той самий tier, що й MISS. Чому:
- Nuestro pricing está calibrado según el valor de negocio del endpoint, no según el coste de CPU.
/v1/chartcuesta lo mismo tanto si la carta se calculó de nuevo como si vino de la caché: el cliente recibió la misma carta. - Прозорість. Не хочемо ситуації коли один user-base платить за MISS, а інший за HIT (теоретично через “пощастило з кешем”). Pricing predictable.
- Cache infrastructure: це інфра, не value-add. Ми її субсидуємо у tier’і.
Але це не значить що X-Cache беззмістовний у pricing-контексті - він видимо показує архітектурні можливості для клієнта (див. наступний розділ).
Qué hacer con esto del lado del cliente
Sección titulada «Qué hacer con esto del lado del cliente»Чотири практичні pattern-и:
1. Capa de caché del lado del cliente para MISS
Sección titulada «1. Capa de caché del lado del cliente para MISS»Якщо ви бачите X-Cache: MISS для запиту, який сценарієм може повторитись (натальна карта тієї самої людини), кешуйте локально у Redis/Memcached/IndexedDB. Server-side кеш у нас має TTL і evict policy - ваш клієнтський шар з контрольованим 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. Batch + dedupe en el backend
Sección titulada «2. Batch + dedupe en el backend»Якщо ваш сервіс приймає масові запити на однакові birth-data (онбординг кампанія, де колеги тестують однаковими демо-даними), використовуйте промісовий dedupe:
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;}Це не зекономить credits (кожен виклик все одно зараховує), але прибирає затори при concurrency-сплесках.
3. Pre-warm de rutas críticas
Sección titulada «3. Pre-warm de rutas críticas»Якщо в продукті є ритуальні чарти (популярні daily-horoscope знаки), pre-warm-те їх scheduled cron-ом. Перший виклик дня - MISS, всі наступні до evict-у - HIT. Користувач отримує subsecond response.
4. Insight del dashboard: dónde pagas de más
Sección titulada «4. Insight del dashboard: dónde pagas de más»Нова колонка cache hit % у /dashboard/usage за endpoint показує:
- HIT% = 90+ - endpoint добре кешується, ймовірно той самий чарт пересилається кілька разів. Розгляньте client-side dedupe (#2).
- HIT% = 0 і BYPASS: endpoint не кешується дизайном (transits/now, AI). Це нормально.
- HIT% = 50% і MISS: половина запитів несе унікальні параметри, половина: повтори. Worth-while client-side cache.
- HIT% низький + endpoint детермінований: підозріло. Перевірте чи ваш клієнт не додає випадкових fields у payload (timestamps, request-id), які забивають кеш-ключ.
Implementación técnica: para curiosos
Sección titulada «Implementación técnica: para curiosos»Tracking коштує одну колонку у api_request_log.cache_status (enum: MISS|HIT|BYPASS, migration 030). Колонка populate-нута з того ж handler-а, який приймає рішення про кеш-lookup - додатковий запит до DB не робиться.
GET /v1/me/usage/endpoints тепер повертає реальне cache_hit_pct замість null для кожного endpoint-а у вашій історії. SDK-метод client.me.usage.endpoints() отримає поле автоматично (типи у наступному codegen-релізі).
Qué sigue
Sección titulada «Qué sigue»Cache instrumentation відкриває проміжний рівень оптимізацій між “no caching” і “full edge cache”. Наступні штрихи у роадмапі:
Cache-Controlреспонсний заголовок з реальним TTL для кешованих endpoint-ів - дозволить CDN/proxy-кеш на стороні клієнтаIf-None-MatchETags: повторні MISS-перевірки без повного payload-у у відповіді- Per-user cache statistics у dashboard з можливістю invalidate (наприклад, форсовано пересчити certain chart після виправлення birth-time)
Документація - /docs/api/ → Performance & Caching. Конкретний X-Cache reference - у секції headers кожного endpoint-а.
El mismo Swiss Ephemeris que en Solar Fire - en 4 líneas de código.
Clave gratuita sin tarjeta. 5 000 llamadas al mes antes del primer pago.