کیشنگ اور دوبارہ توثیق
روٹ سیگمنٹ کی ترتیب، unstable_cache، revalidateTag / revalidatePath اور stale-while-revalidate۔
روٹ ہینڈلر کے ریسپانس اور ڈیٹا کیش کریں، پھر ٹائمر پر یا ضرورت کے مطابق انہیں ری ویلیڈیٹ کریں۔ جب بیک گراؤنڈ میں ایک ریفریش چل رہا ہو تو پرانی انٹریز فوراً فراہم ہوتی ہیں۔
روٹ ہینڈلرز
GET روٹ ہینڈلرز ڈیفالٹ طور پر ڈائنامک ہوتے ہیں۔ کیشنگ فعال کرنے کے لیے روٹ سیگمنٹ کی کنفگ استعمال کریں:
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-cache | MISS، HIT یا STALE |
Cache-Control | s-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 استعمال کریں:
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 سے زیادہ ہو جائے:
- اگلی ریکویسٹ کو پرانی ویلیو فوراً ملتی ہے (
STALE)۔ - بیک گراؤنڈ میں ایک ریفریش چلتا ہے؛ بیک وقت آنے والی ریکویسٹس اسے شیئر کرتی ہیں۔
- اگر ریفریش ایرر تھرو کرے تو پرانی ویلیو فراہم ہوتی رہتی ہے اور ایرر لاگ ہوتا ہے۔
Vercel اور Cloudflare پر، بیک گراؤنڈ ریفریش waitUntil() کے ساتھ رجسٹر ہوتے ہیں۔ ایک سال سے زیادہ پرانی انٹریز ہمیشہ فور گراؤنڈ میں دوبارہ کمپیوٹ ہوتی ہیں۔
ضرورت کے مطابق ری ویلیڈیشن
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 کو ڈیفالٹ ایکسپورٹ کرتا ہو:
export default defineConfig({ cacheHandler: "./cache-handler.ts" });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استعمال کرتا ہے)۔ ڈیپلائے کرنا دیکھیں۔