کیشنگ اور دوبارہ توثیق

روٹ سیگمنٹ کی ترتیب، ⁦unstable_cache⁩، ⁦revalidateTag / revalidatePath⁩ اور ⁦stale-while-revalidate⁩۔

روٹ ہینڈلر کے ریسپانس اور ڈیٹا کیش کریں، پھر ٹائمر پر یا ضرورت کے مطابق انہیں ری ویلیڈیٹ کریں۔ جب بیک گراؤنڈ میں ایک ریفریش چل رہا ہو تو پرانی انٹریز فوراً فراہم ہوتی ہیں۔

روٹ ہینڈلرز

GET روٹ ہینڈلرز ڈیفالٹ طور پر ڈائنامک ہوتے ہیں۔ کیشنگ فعال کرنے کے لیے روٹ سیگمنٹ کی کنفگ استعمال کریں:

app/api/posts/route.tsts
export const revalidate = 60;export async function GET() {  const posts = await db.posts.latest();  return Response.json(posts);}
ایکسپورٹرویہ
(کوئی نہیں)ہر ریکویسٹ پر چلتا ہے
dynamic = "force-static"ری ویلیڈیٹ ہونے تک کیش میں رہتا ہے
revalidate = Nکیش میں رہتا ہے؛ N سیکنڈ بعد پرانا ہو جاتا ہے
revalidate = 0 یا dynamic = "force-dynamic"ہر ریکویسٹ پر چلتا ہے

dynamic کی دوسری ویلیوز TX031 کے ساتھ ناکام ہوتی ہیں۔ ان میں Next.js کی "error" بھی شامل ہے، کیونکہ Text.js معلوم نہیں کر سکتا کہ ہینڈلر کب ریکویسٹ پڑھتا ہے۔

کیش شدہ ہینڈلرز کو ہر پاتھ نیم کے لیے ایک انٹری ملتی ہے، اور ان کی request ویسی ہوتی ہے جیسی بلڈ کے وقت ہوتی: کوئری اسٹرنگ، ہیڈرز، کوکیز یا باڈی کے بغیر۔ انہیں ڈائنامک ہینڈلر میں پڑھیں۔ صرف GET اور HEAD کیش ہوتے ہیں۔ 5xx اسٹیٹس، Set-Cookie ہیڈر، یا Cache-Control: private / no-store والے ریسپانس واپس آتے ہیں مگر کبھی اسٹور نہیں ہوتے۔

ہیڈرز

کیش شدہ ریسپانس میں یہ شامل ہوتے ہیں:

ہیڈرویلیو
x-textjs-cacheMISS، HIT یا STALE
Cache-Controls-maxage=N, stale-while-revalidate=<1 year − N>، یا force-static کے لیے s-maxage=31536000

جب مڈل ویئر ریکویسٹ کے لیے کوکیز سیٹ کرتا ہے، ری رائٹ کرتا ہے یا ریکویسٹ ہیڈرز اوور رائڈ کرتا ہے تو بننے والا ہیڈر private, no-cache, no-store, max-age=0, must-revalidate ہو جاتا ہے، اس لیے مشترکہ کیش کسی وزیٹر کے لیے مخصوص فیصلے کو کبھی دوبارہ استعمال نہیں کرتے۔ ہینڈلر کا سیٹ کردہ Cache-Control ہیڈر برقرار رہتا ہے۔

text dev میں سیگمنٹ کنفگ لاگو ہوتی ہے مگر کچھ اسٹور نہیں ہوتا، اس لیے ہر ریکویسٹ ہینڈلر کو چلاتی ہے۔

ڈیٹا کیش

کسی بھی async فنکشن کو کیش کرنے کے لیے @textjs/app/cache سے unstable_cache استعمال کریں:

lib/posts.tsts
import { unstable_cache } from "@textjs/app/cache";export const getPosts = unstable_cache(  async (author: string) => db.posts.byAuthor(author),  ["posts"],  { tags: ["posts"], revalidate: 300 },);

کلید میں کلید کے حصے اور آرگیومنٹس شامل ہوتے ہیں، جن کی انکوڈنگ ویلیو کے لحاظ سے ہوتی ہے (undefined اور null، Map، Set، Date اور URL آرگیومنٹس الگ الگ رہتے ہیں)۔ کلید کے حصوں کے بغیر، فنکشن کا سورس اور اس کی تخلیق کی جگہ اس کی شناخت کرتے ہیں؛ جب بھی فنکشن بیرونی ویلیوز کو کلوزر میں رکھتا ہو تو کلید کے حصے پاس کریں، مثلاً جب وہ ہر ریکویسٹ پر یا کسی لوپ میں بنتا ہو۔ نتائج JSON میں سیریلائز ہوتے ہیں، اس لیے ہر کال ایک نئی کاپی واپس کرتی ہے (اور Date آبجیکٹس اسٹرنگز کے طور پر واپس آتے ہیں)؛ جو نتیجہ سیریلائز نہ ہو سکے وہ ایرر تھرو کرتا ہے۔ cache(fn, { key, tags, revalidate }) یہی ترتیبات ایک آپشنز آبجیکٹ کے طور پر لیتا ہے۔

کیش شدہ روٹ ہینڈلر کے اندر، ڈیٹا انٹریز اپنے ٹیگز اور اپنی سب سے مختصر revalidate مدت روٹ تک پہنچاتی ہیں: "posts" کو ری ویلیڈیٹ کرنے سے /api/posts بھی ریفریش ہوتا ہے۔ revalidate: 0 والی ڈیٹا کال روٹ کو ڈائنامک بنا دیتی ہے۔

ری ویلیڈیشن کے دوران پرانی ویلیو

جب کسی انٹری کی عمر revalidate سے زیادہ ہو جائے:

  1. اگلی ریکویسٹ کو پرانی ویلیو فوراً ملتی ہے (STALE)۔
  2. بیک گراؤنڈ میں ایک ریفریش چلتا ہے؛ بیک وقت آنے والی ریکویسٹس اسے شیئر کرتی ہیں۔
  3. اگر ریفریش ایرر تھرو کرے تو پرانی ویلیو فراہم ہوتی رہتی ہے اور ایرر لاگ ہوتا ہے۔

⁦Vercel⁩ اور Cloudflare پر، بیک گراؤنڈ ریفریش waitUntil() کے ساتھ رجسٹر ہوتے ہیں۔ ایک سال سے زیادہ پرانی انٹریز ہمیشہ فور گراؤنڈ میں دوبارہ کمپیوٹ ہوتی ہیں۔

ضرورت کے مطابق ری ویلیڈیشن

app/api/revalidate/route.tsts
import { revalidatePath, revalidateTag } from "@textjs/app/cache";export async function POST(request: Request) {  // Anyone can POST here: require a secret shared with your CMS or webhook.  if (request.headers.get("authorization") !== `Bearer ${process.env.REVALIDATE_SECRET}`) {    return new Response("Unauthorized", { status: 401 });  }  await revalidateTag("posts");  await revalidatePath("/api/feed");  return Response.json({ revalidated: true });}
کالان ویلیڈیٹ ہونے والا ڈیٹا
revalidateTag("posts")posts ٹیگ والا تمام ڈیٹا؛ اگلی ریکویسٹ دوبارہ کمپیوٹ کرتی ہے
revalidateTag("posts", "max")اسے پرانا نشان زد کرتی ہے؛ ریفریش کے دوران اگلی ریکویسٹ کو پرانا ڈیٹا ملتا ہے
revalidatePath("/api/feed")وہ پاتھ
revalidatePath("/api/posts/[id]")ڈائنامک روٹ کا ہر پاتھ
revalidatePath("/api", "layout")/api کے تحت تمام ڈیٹا

دونوں ایک پرامس واپس کرتے ہیں۔ اِن میموری اسٹور کے ساتھ ان ویلیڈیشن فوری ہوتی ہے؛ جب کسٹم اسٹور غیر ہم وقت ہو تو اس پر await استعمال کریں۔

کسٹم کیش اسٹورز

ڈیفالٹ اسٹور ہر سرور انسٹینس کے لیے ایک اِن میموری LRU ہے (1,000 انٹریز، تقریباً 50 MB)۔ انسٹینسز کے درمیان کیش شیئر کرنے کے لیے، cacheHandler کو ایسے ماڈیول کی طرف پوائنٹ کریں جو CacheStore کو ڈیفالٹ ایکسپورٹ کرتا ہو:

text.config.tsts
export default defineConfig({ cacheHandler: "./cache-handler.ts" });
cache-handler.tsts
import type { CacheStore } from "@textjs/app/cache";const store: CacheStore = {  async get(key) { return redis.get(key).then((v) => (v ? JSON.parse(v) : undefined)); },  async set(key, entry) { await redis.set(key, JSON.stringify(entry)); },  async delete(key) { await redis.del(key); },  async markTags(tags, mode, at) { for (const t of tags) await redis.hset(`tag:${t}`, mode, at); },  async getTagState(tags) { /* max expiredAt / staleAt across tags */ return { expiredAt: 0, staleAt: 0 }; },};export default store;

انٹریز سادہ JSON ہوتی ہیں۔ اس کے بجائے setCacheStore(store) رن ٹائم پر اسٹور انسٹال کرتا ہے۔

پلیٹ فارم سے متعلق معلومات

  • ہر سرورلیس انسٹینس (Vercel فنکشنز، Cloudflare آئسولیٹس) کا اپنا اِن میموری کیش ہوتا ہے۔ Cache-Control: s-maxage پلیٹ فارم کے CDN کو بھی ریسپانس کیش کرنے دیتا ہے؛ ضرورت کے مطابق ری ویلیڈیشن CDN کو صاف نہیں کرتی۔ جب revalidateTag کو ہر انسٹینس تک پہنچنا ہو تو مشترکہ cacheHandler استعمال کریں۔
  • Cloudflare کے لیے nodejs_compat فلیگ ضروری ہے (کیش AsyncLocalStorage استعمال کرتا ہے)۔ ڈیپلائے کرنا دیکھیں۔
⁦GitHub⁩ پر اس صفحے میں ترمیم کریں