SENT Digital Agency
INITIATING SYSTEM...0%
Sanity CMS: حل چالش Latency و پایداری در ایران با معماری Next.js ISR
۱۸ آذر ۱۴۰۴

Sanity CMS: حل چالش Latency و پایداری در ایران با معماری Next.js ISR

مقدمه

در سال‌های اخیر، معماری Headless CMS به استاندارد توسعه محصولات دیجیتال مدرن تبدیل شده است. Sanity.io با ارائه Schema-as-Code و GROQ Query Language، انتخاب اول تیم‌های مهندسی در جهان است. اما استفاده از آن در کشورهای با محدودیت زیرساختی مانند ایران، چالش‌های فنی جدی (Latency بالا و محدودیت‌های دسترسی) به همراه دارد.

این مقاله از سری مستندات فنی SENT، برای حل این چالش با استفاده از معماری Next.js ISR و Edge Caching اختصاص دارد. اگر به دنبال راهکارهای معماری مشابه برای پروژه خود هستید، خدمات طراحی سیستم‌های Enterprise ما می‌تواند کمک کند.

بخش اول: تحلیل چالش

۱.۱ ماهیت مسئله

Sanity.io از معماری API-First استفاده می‌کند. در تست‌های ما بر روی یک پروژه سازمانی در ایران، سه چالش اصلی شناسایی شد:

۱. تأخیر شبکه (Network Latency)

به دلیل نبود Edge Location در خاورمیانه و routing نامناسب، میانگین TTFB برای درخواست‌های مستقیم API بین ۲۰۰۰ تا ۴۰۰۰ میلی‌ثانیه بود.

۲. قابلیت اطمینان (Reliability)

وابستگی Runtime به API خارجی به معنی آسیب‌پذیری در برابر اختلالات اینترنت بین‌المللی است.

۳. هزینه

برای سایتی با ۵۰۰ هزار بازدید ماهانه، درخواست مستقیم به API، هزینه‌های Bandwidth غیرمنطقی ایجاد می‌کند.

نمودار مقایسه زمان پاسخ سرور (TTFB) قبل و بعد از پیاده‌سازی معماری ISR؛ کاهش از ۲۱۰۰ به ۸۵ میلی‌ثانیه

۱.۲ راه‌حل‌های ناکارآمد

برخی از رویکردهای رایج که جواب نمی‌دهند:‌

Client-Side Fetching: بارگذاری محتوا پس از رندر اولیه که SEO را خراب می‌کند.Basic Server Caching: همچنان به API calls اولیه با Latency بالا نیاز دارد.
استفاده از VPN: غیرقابل‌اعتماد و افزایش complexity

بخش دوم: راه‌حل مهندسی

ما معماری را بر سه اصل بنا کردیم:
Decoupling (جداسازی لایه داده از کاربر)
Edge Caching
Incremental Updates

۲.۱ معماری ISR (Incremental Static Regeneration)

به جای Fetch کردن داده در لحظه درخواست (SSR که کند است)، یا در زمان Build (Static که قدیمی می‌شود)، از ISR استفاده کردیم.

JavaScript
// pages/posts/[slug].js
export async function getStaticProps({ params }) {
const query = *[_type == "post" && slug.current == $slug][0];
const post = await fetchWithFallback(query, { slug: params.slug });

return {
props: { post },
revalidate: 60, // تلاش برای به‌روزرسانی هر ۶۰ ثانیه
};
}

مکانیسم کار:


1. کاربر اول محتوای Static را می‌بیند. (سریع)
2. در Background، Next.js محتوا را از Sanity می‌گیرد.
3. کاربرِ بعدی، نسخه تازه را دریافت می‌کند.

فلوچارت فرآیند کار Incremental Static Regeneration در Next.js: از ارائه محتوای Static تا به‌روزرسانی Background

۲.۲ لایه امنیتی؛ Reverse Proxy

برای اطمینان از دسترسی پایدار به Sanity API در زمان Build (به‌ویژه در محیط‌های CI/CD داخل ایران)، یک لایه Reverse Proxy شفاف پیاده‌سازی شد.

ویژگی‌های این لایه:

Routing درخواست‌ها از طریق سرور واسط
Retry خودکار با استراتژی Backoff در صورت Timeout
Logging دقیق برای Monitoring سلامت ارتباط.

نکته مهم:
ا
ین لایه فقط در Build Time فعال است و هیچ تأثیری بر سرعت کاربر نهایی ندارد. (چون محتوا Static است)

۲.۳ استراتژی Fallback چند لایه

برای تضمین Uptime نزدیک به ۱۰۰٪، یک سیستم caching چند لایه طراحی کردیم:

JavaScript
// lib/sanity-client.js
import NodeCache from 'node-cache';
import fs from 'fs/promises';
const memoryCache = new NodeCache({ stdTTL: 3600 });

export async function fetchWithFallback(query, params) {
  const cacheKey = JSON.stringify({ query, params });
  
  try {
    // سطح ۱: دریافت مستقیم از Sanity با Timeout
    const result = await Promise.race([
      sanityClient.fetch(query, params),
      new Promise((_, reject) =>
        setTimeout(() => reject(new Error('Timeout')), 5000)
      )
    ]);
    
    // ذخیره در Memory و Disk
    memoryCache.set(cacheKey, result);
    await saveToDisk(cacheKey, result); 
    return result;

  } catch (error) {
    console.warn('Sanity fetch failed, using fallback...');
    
    // سطح ۲: Memory Cache
    const cached = memoryCache.get(cacheKey);
    if (cached) return cached;

    // سطح ۳: Disk Cache (آخرین نسخه موفق)
    const diskCached = await loadFromDisk(cacheKey);
    if (diskCached) return diskCached;

    // سطح ۴: Static Fallback (جلوگیری از Crash)
    return {
      title: 'محتوا در حال به‌روزرسانی...',
      body: [],
      publishedAt: new Date().toISOString()
    };
  }
}


چهار سطح محافظت:

1. API مستقیم (با Timeout سخت‌گیرانه)
2. Memory Cache (سریع‌ترین)
3. Disk Cache (پایدارترین)
4. Static Fallback (آخرین خط دفاعی)

نمودار هرمی استراتژی Fallback چهار لایه‌ای؛ از API مستقیم تا Static Fallback برای تضمین Uptime 99.99%

4. Static Fallback (آخرین خط دفاعی)
۲.۴ به‌روزرسانی آنی با Webhooks

برای اینکه تیم محتوا تغییرات را بلافاصله ببیند، از Webhooks استفاده کردیم:

JavaScript
// pages/api/revalidate.js
export default async function handler(req, res) {
const signature = req.headers['sanity-webhook-signature'];

if (!isValidSignature(req.body, signature)) {
return res.status(401).json({ message: 'Invalid signature' });
}

try {
const { _type, slug } = req.body;
await res.revalidate(/${_type}/${slug.current});
return res.json({ revalidated: true });
} catch (err) {
return res.status(500).json({ message: 'Error revalidating' });
}
}


جریان کار:

1. محتوا در Sanity منتشر می‌شود.
2. Webhook به Next.js ارسال می‌شود.
3. صفحه مربوط در Background rebuild می‌شود.
4. کاربران بعدی محتوای تازه را می‌بینند. (معمولاً < ۵ ثانیه)

فلوچارت فرآیند Webhook از Sanity به Next.js؛ از انتشار محتوا تا نمایش لحظه‌ای در کمتر از ۵ ثانیه

بخش سوم: نتایج عملیاتی

پیاده‌سازی این معماری روی یک پلتفرم e-commerce با ۵۰۰ هزار بازدید ماهانه، نتایج زیر را ثبت کرد:

شاخصقبل از اجرابعد از معماری SENTبهبود
TTFB (تهران)۲۱۰۰ میلی‌ثانیه۸۵ میلی‌ثانیه ۹۶٪ 🚀
LCP۴٫۲ ثانیه۱٫۱ ثانیه۷۴٪
API Calls (ماهانه)۵۰۰,۰۰۰۵۰,۰۰۰۹۰٪ کاهش
هزینه زیرساخت۱۲۰ میلیون تومان۱۷ میلیون تومان۸۶٪ صرفه‌جویی
Uptime۹۸٫۵٪۹۹٫۹۹٪پایدار

نمودار مقایسه شاخص‌های عملکرد قبل و بعد از معماری SENT؛ ۹۶٪ بهبود TTFB، ۸۶٪ کاهش هزینه، ۹۰٪ کاهش API calls

ابزار اندازه‌گیری:
WebPageTest (سرور تهران) + Vercel Analytics

تأثیر بر کسب‌وکار


Bounce Rate: کاهش ۳۵٪
Conversion Rate: افزایش ۲۲٪ در صفحات محصول
Support Tickets: حذف کامل تیکت‌های "سایت کُند"

نتیجه‌گیری

استفاده از Sanity CMS در ایران غیرممکن نیست، بلکه نیازمند مهندسی دقیق است. با ترکیب ISR، Reverse Proxy و استراتژی Fallback چند لایه، ما تجربه کاربری جهانی را با زیرساخت محلی ترکیب کردیم.

سه نکته مهم:
1. Latency API را با Static Generation از مسیر حساس حذف کنید.
2. همیشه چند لایه Fallback داشته باشید.
3. از Webhooks برای به‌روزرسانی فوری استفاده کنید.

منابع و مراجع

1. [Next.js ISR Documentation](https://nextjs.org/docs/pages/guides/incremental-static-regeneration)

2. [Sanity Webhooks Guide]
(https://www.sanity.io/guides/sanity-webhooks-and-on-demand-revalidation-in-nextjs)

3. [How ISR Works - FreeCodeCamp
(https://www.freecodecamp.org/news/how-incremental-static-regeneration-isr-works-in-nextjs/)

هویت SENT

SENT گروهی از مهندسان نرم‌افزار است که بر روی طراحی و پیاده‌سازی سیستم‌های Enterprise برای برندهای B2B تمرکز دارد. تخصص ما حل چالش‌های معماری پیچیده، یکپارچه‌سازی سیستم‌ها و ارائه راه‌حل‌های مقیاس‌پذیر است.


Back to Codex
End of Transmission