Server-side cache ở chúng tôi đã hoạt động lâu rồi - tính toán chart xác định cho cùng date/time/lat/lon được trả về từ cache, không phải tính lại từ đầu. Tuy nhiên khách hàng này không thấy. Trong dashboard, cột “cache hit %” hiển thị – vì backend ghi cache-outcome vào metric nội bộ, không phải vào phản hồi.
Bây giờ mỗi response mang một trong ba tiêu đề:
X-Cache: HIT # обслужено з кешуX-Cache: MISS # обчислено з нуля, результат збереженоX-Cache: BYPASS # не кешується за дизайномĐây là một thay đổi nhỏ - tiêu đề cộng thêm một cột trong api_request_log - nhưng nó mở ra một lớp tối ưu hóa hoàn toàn mà trước đây là điểm mù.
Cách hoạt động: ví dụ
Phần tiêu đề “Cách hoạt động: ví dụ”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: MISSThực hiện lần hai với cùng một body request:
# X-Cache: HITĐối với các endpoint kiểu /v1/transits/now (thời gian động) - X-Cache: BYPASS, vì kết quả phụ thuộc vào Date.now() hiện tại và việc cache không có ý nghĩa.
Các endpoint trả về gì
Phần tiêu đề “Các endpoint trả về gì”Không phải tất cả các endpoint đều được cache - và điều này có ý định. Phân loại:
- Các tính toán chart xác định (
/v1/chart,/v1/houses,/v1/aspects,/v1/synastry,/v1/dasha/*,/v1/vargas/*) - được cache hoàn toàn. Mong đợi pattern MISS → HIT. - Phụ thuộc thời gian (
/v1/transits/now,/v1/horoscope/today,/v1/moon/phase-now) -BYPASS. Cache có thể chỉ chính xác đến cuối phút, vì vậy đơn giản là không cache überhaupt. - Nội dung được tạo bởi AI (
/v1/horoscope/personal,/v1/interpret/*):BYPASS. Các phản hồi LLM không xác định ngay cả với cùng một prompt, việc cache = cố định ngẫu nhiên. - Các endpoint render (
/v1/render/*):MISS/HITcho một số,BYPASScho những endpoint nhận payload lớn (eclipse-path có 500 điểm).
Đánh dấu trên endpoint cụ thể có thể thấy ngay từ response - không cần đọc tài liệu để biết có được cache hay không.
Ảnh hưởng đến giá: các request được cache vẫn tốn phí
Phần tiêu đề “Ảnh hưởng đến giá: các request được cache vẫn tốn phí”Đây là điều quan trọng nhất để hiểu - các request được cache vẫn trừ credits trên cùng một tier như MISS. Lý do:
- Pricing của chúng tôi được calibrated dựa trên giá trị kinh doanh của endpoint, không phải dựa trên chi phí CPU.
/v1/chartcó giá như nhau, dù chart được tính lại hay lấy từ cache - khách hàng nhận được cùng một chart. - Minh bạch. Chúng tôi không muốn có tình huống một nhóm người dùng trả tiền cho MISS trong khi nhóm khác trả cho HIT (lý thuyết do “may mắn với cache”). Giá cả có thể dự đoán được.
- Cơ sở hạ tầng cache: đây là infra, không phải giá trị tăng. Chúng tôi hỗ trợ nó trong tier.
Nhưng điều này không có nghĩa là X-Cache vô nghĩa trong bối cảnh giá - nó rõ ràng cho thấy cơ hội kiến trúc cho khách hàng (xem phần tiếp theo).
Điều gì cần làm phía client
Phần tiêu đề “Điều gì cần làm phía client”Bốn mẫu thực tiễn:
1. Lớp cache phía client cho MISS
Phần tiêu đề “1. Lớp cache phía client cho MISS”Nếu bạn thấy X-Cache: MISS cho một request có thể lặp lại (bản đồ natal của cùng một người), hãy cache cục bộ ở Redis/Memcached/IndexedDB. Server-side cache của chúng tôi có TTL và chính sách evict - lớp cache phía client của bạn với TTL được kiểm soát sẽ tránh trừ credits thừa.
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 ở backend
Phần tiêu đề “2. Batch + dedupe ở backend”Nếu dịch vụ của bạn chấp nhận các request lớn có cùng birth-data (chiến dịch onboarding, nơi đồng nghiệp thử cùng dữ liệu demo), hãy sử dụng dedupe dựa trên promise:
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;}Điều này không tiết kiệm credits (mỗi lệnh gọi vẫn được tính), nhưng nó loại bỏ tắc nghẽn trong các đợt tăng cường concurrency.
3. Pre-warm các đường dẫn quan trọng
Phần tiêu đề “3. Pre-warm các đường dẫn quan trọng”Nếu sản phẩm của bạn có các chart rituál (các dấu horoscope hàng ngày phổ biến), hãy pre-warm chúng bằng cron được lên lịch. Lần gọi đầu tiên trong ngày - MISS, tất cả các lần gọi tiếp theo trước khi evict - HIT. Người dùng nhận được phản hồi subsecond.
4. Insight từ dashboard: nơi bạn trả phí thừa
Phần tiêu đề “4. Insight từ dashboard: nơi bạn trả phí thừa”Cột mới cache hit % trong /dashboard/usage theo endpoint hiển thị:
- HIT% = 90+ - endpoint được cache tốt, có khả năng cùng một chart được gửi nhiều lần. Hãy cân nhắc client-side dedupe (#2).
- HIT% = 0 và BYPASS: endpoint không được cache theo thiết kế (transits/now, AI). Điều này là bình thường.
- HIT% = 50% và MISS: một nửa request mang tham số duy nhất, nửa còn lại là lặp lại. Worth-while để có client-side cache.
- HIT% thấp + endpoint xác định: nghi ngờ. Kiểm tra xem khách hàng của bạn có thêm các trường ngẫu nhiên vào payload (timestamps, request-id) không, chúng làm đầy khóa cache.
Triển khai kỹ thuật: cho những người tò mò
Phần tiêu đề “Triển khai kỹ thuật: cho những người tò mò”Tracking chỉ cần một cột trong api_request_log.cache_status (enum: MISS|HIT|BYPASS, migration 030). Cột được điền từ chính handler đó đưa ra quyết định về tra cứu cache - không có truy vấn DB bổ sung.
GET /v1/me/usage/endpoints giờ trả về cache_hit_pct thực thay vì null cho mỗi endpoint trong lịch sử của bạn. Phương thức SDK client.me.usage.endpoints() sẽ nhận trường này tự động (kiểu trong bản phát hành codegen tiếp theo).
Tiếp theo là gì
Phần tiêu đề “Tiếp theo là gì”Việc đo lường cache mở ra một mức tối ưu trung gian giữa “không có cache” và “cache toàn bộ edge”. Các bước tiếp theo trong roadmap:
- Tiêu đề phản hồi
Cache-Controlvới TTL thực cho các endpoint được cache - sẽ cho phép CDN/proxy cache phía client - ETags
If-None-Match: các lần kiểm tra MISS lặp lại mà không cần payload đầy đủ trong phản hồi - Thống kê cache theo mỗi người dùng trong dashboard có khả năng invalidate (ví dụ, ép tính lại một chart nhất định sau khi sửa birth-time)
Tài liệu - /docs/api/ → Performance & Caching. Tham chiếu cụ thể X-Cache - trong phần headers của mỗi endpoint.
Chính Swiss Ephemeris giống như trong Solar Fire - chỉ trong 4 dòng code.
Khóa API miễn phí không cần thẻ. 5.000 lượt gọi/tháng trước lần thanh toán đầu tiên.