IlmHamroh
JavaScript Full-stack/30-qism. NestJS38/65-dars14 daqiqa
Mundarija (23)

NestJS keshlash: CacheModule, CacheInterceptor va Redis (Keyv)

Qisqacha: @nestjs/cache-manager — Nest'ning kesh moduli: CacheModule.register() kesh xizmatini beradi, uni @Inject(CACHE_MANAGER) bilan olib get, set, del qilasiz. Ombor — cache-manager 7 va Keyv: sukutda xotira, @keyv/redis bilan Redis. @UseInterceptors(CacheInterceptor) GET javobini avtomatik keshlaydi — kalit URL. Qulay, lekin uch tuzoq bor: yozuvdan keyin eskirgan javob (TTL tugaguncha), bitta URL — hamma foydalanuvchi uchun bitta javob, invalidatsiya esa qo'lda va kalitlarni bilishni talab qiladi. Shuning uchun vazifalar-api 27-qismdagi KeshliOmbor da qoladi.

Bu darsda

  • CacheModule.register / registerAsync va Keyv omborlarini (xotira, Redis) ulaysiz.
  • CACHE_MANAGER bilan qo'lda get / set / del qilasiz va TTL birligini bilasiz.
  • CacheInterceptor, @CacheKey, @CacheTTL qanday kalit yasashini haqiqiy chiqishda ko'rasiz.
  • Eskirgan javob, foydalanuvchilar aralashuvi va xotira omboridagi havola tuzog'ini o'z ko'zingiz bilan ko'rasiz.
  • Kanon nega CacheInterceptor emas, avlod kalitli KeshliOmbor ni tanlaganini tushuntirasiz.

Oldin bilishingiz kerak: Caching naqshlari va invalidatsiya, String, TTL va kalit nomlash, Interceptor'lar va RxJS, Repository naqshi va qatlamlar, Swagger: @nestjs/swagger.

O'tgan darsda vazifalar-api ga hujjat qo'shildi. Bu dars — tajriba darsi: Nest'ning standart kesh vositasini 27-qismda o'zimiz qurgan kesh bilan solishtiramiz.

1. Nega bu kerak?

27-qismda kesh qurgandik (Caching naqshlari va invalidatsiya): Redis'da ro'yxat javobi saqlanadi, bazaga har safar bormaymiz. Eng qiyin qismi — keshlashning o'zi emas, invalidatsiya: ma'lumot o'zgarganda eski nusxani o'z vaqtida unutish. "Kompyuter fanidagi ikki qiyin narsa" haqidagi mashhur hazil aynan shu haqda.

Nest'da kesh uchun tayyor modul bor. Savol: u bizning muammoni hal qiladimi yoki yangisini keltiradimi?

O'xshatish: do'kon peshtaxtasidagi narx yorlig'i. Har mijozga narxni omborxonadan so'rab kelish o'rniga, yorliq yopishtirasiz — tez. Lekin narx o'zgarsa, yorliqni almashtirish kerak. Agar yorliqlar "qaysi javonda turganiga" qarab yopishtirilsa, bitta mahsulot uch javonda bo'lsa — uchalasini topib almashtirish kerak. Bittasi unutilsa, mijoz eski narxni ko'radi.

2. CacheModule va CACHE_MANAGER

2.1 Ulash

ts
CacheModule.registerAsync({
  useFactory: () => ({
    stores: [new KeyvRedis("redis://127.0.0.1:6383")],
    ttl: 60_000,
  }),
}),
  • stores — Keyv omborlari ro'yxati. cache-manager 6 dan boshlab o'z omborlari o'rniga Keyv ishlatadi: @keyv/redis, @keyv/postgres va boshqalar. stores berilmasa — xotira (jarayon ichidagi Map).
  • ttl: 60_000 — yashash vaqti millisekundda. 27-qismdagi Redis EX 60 soniyada edi (String, TTL va kalit nomlash); bu yerda 60 deb yozsangiz — 60 ms, kesh deyarli ishlamaydi.
  • registerAsync — sozlama config'dan kelishi uchun (@nestjs/config darsidagi forRootAsync naqshi). isGlobal: true ham bor.

Versiyalar — kanon tajribasidagi: @nestjs/cache-manager 12.0.1, cache-manager 7.2.9, @keyv/redis 6.1.0.

2.2 Qo'lda ishlatish

ts
constructor(@Inject(CACHE_MANAGER) private readonly kesh: Cache) {}

await this.kesh.set("vz:1:royxat", natija, 60_000);
const bor = await this.kesh.get<RoyxatNatija>("vz:1:royxat");
await this.kesh.del("vz:1:royxat");

CACHE_MANAGER — token (Custom provider'lar), Cache — cache-manager turi. Hamma metod async: ombor Redis bo'lsa, har chaqiruv — tarmoq aylanishi. Bu shakl — 27-qismdagi cache-aside naqshining o'zi, faqat klient boshqa.

3. CacheInterceptor — avtomatik keshlash

3.1 Kanon tajribasi

ts
@Controller("v")
class C {
  constructor(@Inject(CACHE_MANAGER) private readonly kesh: Cache) {}
  @Get() @UseInterceptors(CacheInterceptor) @CacheTTL(60_000)
  royxat() {
    ombordanOqish++;
    return { vazifalar };
  }
  @Post() yarat(@Body() b: { matn: string; tozala?: boolean }) {
    vazifalar.push({ id: vazifalar.length + 1, matn: b.matn });
    // CacheInterceptor kalitni o'zi qo'yadi — URL; invalidatsiya —
    // qo'lda, kalitni bilish kerak
    return b.tozala === true
      ? this.kesh.del("/v")
        .then(() => ({ ok: true, tozalandi: true }))
      : { ok: true };
  }
}

Bu kanon tajribasi kodi, telefon uchun bo'lindi. CacheInterceptor — interceptor: u handler'dan oldin keshga qaraydi. Javob bor bo'lsa — handler'ni chaqirmasdan qaytaradi. Yo'q bo'lsa — handler natijasini keshga yozadi. @CacheTTL(60_000) — shu marshrut uchun TTL. ombordanOqish — handler necha marta haqiqatan ishlaganini sanaydi. vazifalar — xotiradagi massiv, "ombor" o'rnida.

Kanon chiqishi — Redis bilan (kanon o'lchovi, IlmHamroh, 2026-10, NestJS 12.2.0). Har qatorda ikki narsaga qarang: javobdagi ro'yxat va "ombordan o'qish" soni. Son o'zgarmasa — javob keshdan kelgan:

text
1) GET /v → 200 {"vazifalar":[{"id":1,"matn":"Non"}]}; ombordan o'qish: 1
2) GET /v (yana) → 200 {"vazifalar":[{"id":1,"matn":"Non"}]}; ombordan o'qish: 1 (keshdan)
3) GET /v?x=1 → 200 {"vazifalar":[{"id":1,"matn":"Non"}]}; ombordan o'qish: 2 — boshqa URL = boshqa kalit
4) POST "Sut" (tozalamasdan) keyin GET /v → 200 {"vazifalar":[{"id":1,"matn":"Non"}]} — ESKIRGAN (TTL 60 s gacha)
5) POST "Olma" + kesh.del("/v") → 200 {"vazifalar":[{"id":1,"matn":"Non"},{"id":2,"matn":"Sut"},{"id":3,"matn":"Olma"}]}; lekin /v?x=1 → 200 {"vazifalar":[{"id":1,"matn":"Non"}]} — u kalit tozalanmadi
6) Redis'dagi kalitlar (keyv prefiksi bilan): ["/v","/v?x=1","vz:1:avlod"]
7) o'rtacha (bitta jarayon, ketma-ket): kesh HIT 1.17 ms, MISS (+del) 1.96 ms — "ombor" bu yerda xotiradagi massiv (0 ms): kesh yutuq bermaydi

3.2 Qatorma-qator

  1. Birinchi GET — keshda yo'q, handler ishladi (1).
  2. Ikkinchi GET — keshdan; handler chaqirilmadi (hali 1).
  3. /v?x=1 — boshqa kalit, handler yana ishladi (2). Kalit — to'liq URL, query bilan. ?sort=matn, ?limit=10, ?x=1 — har biri alohida kesh yozuvi.
  4. POST'dan keyin — "Sut" qo'shildi, lekin GET hali eski ro'yxatni berdi. Kesh yozuvdan bexabar: TTL (60 s) tugaguncha mijoz eski ma'lumot ko'radi.
  5. del("/v") — /v toza, yangi ro'yxat keldi. Lekin /v?x=1 hali eski. Invalidatsiya uchun har URL kalitini bilish va o'chirish kerak — query kombinatsiyalari esa cheksiz.
  6. Redis kalitlari — "/v", "/v?x=1": prefikssiz. Xuddi shu Redis'ni boshqa ilova ishlatsa va u ham /v yo'lini keshlasa — kalitlar to'qnashadi. vz:1:avlod — boshqa narsa: 27-qismdagi KeshliOmbor ning kaliti (o'sha Redis'da edi).
  7. Tezlik — HIT 1.17 ms, MISS 1.96 ms. Bu tajribada "ombor" xotiradagi massiv — 0 ms. Kesh Redis'ga tarmoq aylanishini qo'shdi, ombordan esa hech narsa yutmadi. Kesh faqat ombor qimmat bo'lganda (og'ir SQL, tashqi API) foyda beradi. Bitta mashina, ketma-ket o'lchov — nisbatga qarang.

3.3 Kesh so'rov yo'lining qayerida turadi?

CacheInterceptor — interceptor, demak u so'rov yo'lida aniq joyda ishlaydi (Request lifecycle). Buni bilish ikki savolga javob beradi: "keshlangan marshrutda guard ishlaydimi?" va "pipe xatosi keshga tushadimi?"

Tartib Qatlam Keshlangan GET'da nima bo'ladi
1 middleware har safar ishlaydi
2 guard har safar ishlaydi — ruxsat tekshiruvi kesh oldida
3 interceptor (oldin) CacheInterceptor keshga qaraydi; bor bo'lsa — shu yerda qaytadi
4 pipe faqat keshda yo'q bo'lsa
5 handler faqat keshda yo'q bo'lsa
6 interceptor (keyin) handler natijasi keshga yoziladi
7 exception filter xato keshga tushmaydi — faqat muvaffaqiyatli javob yoziladi

Ikkinchi qatorga e'tibor bering: guard kesh oldida turadi, shuning uchun anonim mijoz keshlangan javobni ham ololmaydi. Lekin guard faqat "o'tsinmi?" deb so'raydi — kimning javobi qaytishini u hal qilmaydi. Buni kalit hal qiladi, kalitda esa foydalanuvchi yo'q. «Hamma foydalanuvchiga bitta javob» bo'limidagi tuzoq aynan shu bo'shliqdan chiqadi.

Yana bir qoida Nest kodida yozilgan: CacheInterceptor faqat GET ni keshlaydi (allowedMethods = ['GET'], @nestjs/cache-manager 12.0.1). POST ga qo'yilsa, hech narsa keshlanmaydi va xato ham chiqmaydi — jim o'tadi. Uchinchi qoida ham kodda: keshdan o'qish xato bersa (masalan, Redis uzilgan), interceptor xatoni yutadi va handler'ni chaqiradi. Ya'ni Redis uzilsa API ishlashda davom etadi, faqat sekinroq — kesh "bor bo'lsa yaxshi" qatlam bo'lib qoladi. 27-qismdagi KeshliOmbor ham shunday qilardi.

Tekshirib ko'ring: /v?limit=10&sort=matn va /v?sort=matn&limit=10 — CacheInterceptor uchun bitta kalitmi?

Javob

Yo'q — URL satri boshqa, demak kalit ham boshqa. Ma'nosi bir xil so'rov ikki marta keshlanadi va invalidatsiyada ikkalasini ham topish kerak. 25-qismdagi kanonik so'rov izi (fingerprint) shu muammo uchun edi (Idempotency-Key) — CacheInterceptor buni qilmaydi.

4. Biz ham sinadik — xotira ombori va ikki kutilmagan natija

4.1 Xotira ombori havolani saqlaydi

Redis'siz takrorladik: o'sha controller, CacheModule.register({ ttl: 60_000 }) — stores siz, ya'ni xotira (biz ishga tushirdik: @nestjs/cache-manager 12.0.1, cache-manager 7.2.9, keyv 6.1.0). 1–3 qadamlar kanon bilan bir xil. 4–5 qadamlar esa:

text
4) POST "Sut", keyin GET /v → 200 {"vazifalar":[{"id":1,"matn":"Non"},{"id":2,"matn":"Sut"}]}
5) POST "Olma" + del("/v") → GET /v: 200 {"vazifalar":[{"id":1,"matn":"Non"},{"id":2,"matn":"Sut"},{"id":3,"matn":"Olma"}]}
   GET /v?x=1: 200 {"vazifalar":[{"id":1,"matn":"Non"},{"id":2,"matn":"Sut"},{"id":3,"matn":"Olma"}]}

Eskirgan javob yo'q — "Sut" darhol ko'rindi, /v?x=1 ham yangi. Kesh yaxshiroq ishladimi? Yo'q. Handler { vazifalar } qaytaradi — o'sha massivga havola. Xotira ombori qiymatni nusxalamay saqlaydi (Havola semantikasi). push keshdagi massivni ham o'zgartirdi — kesh "o'z-o'zidan yangilandi". Isboti: handler'ni nusxa qaytaradigan qilsak ({ vazifalar: [...vazifalar] }):

text
4) POST "Sut", keyin GET /v → 200 {"vazifalar":[{"id":1,"matn":"Non"}]}
5) POST "Olma" + del("/v") → GET /v: 200 {"vazifalar":[{"id":1,"matn":"Non"},{"id":2,"matn":"Sut"},{"id":3,"matn":"Olma"}]}
   GET /v?x=1: 200 {"vazifalar":[{"id":1,"matn":"Non"}]}

Endi natija kanon (Redis) bilan bir xil: eskirgan javob va tozalanmagan /v?x=1. Xulosa: lokalda xotira ombori bilan "ishlagan" kesh prodakshnda Redis bilan boshqacha ishlaydi. Redis qiymatni JSON qilib saqlaydi — havola uziladi. Testda xotira, prodakshnda Redis bo'lsa, test xatoni yashiradi.

4.2 Hamma foydalanuvchiga bitta javob

Ikkinchi sinov — "mening vazifalarim" marshruti. Foydalanuvchi sarlavhadan keladi (auth o'rnida, x-foydalanuvchi):

ts
@Controller("mening")
class Mening {
  @Get() @UseInterceptors(CacheInterceptor)
  mening(@Headers("x-foydalanuvchi") kim: string) {
    return { kim, vazifalar: `${kim} ning vazifalari` };
  }
}
text
6) Ali → 200 {"kim":"Ali","vazifalar":"Ali ning vazifalari"}
   Malika → 200 {"kim":"Ali","vazifalar":"Ali ning vazifalari"}

Malika Ali'ning ma'lumotini oldi. URL bir xil (/mening), kalit bir xil — kesh foydalanuvchini bilmaydi. Haqiqiy auth bilan ham shunday: cookie va Authorization sarlavhasi kalitga kirmaydi. Bu shunchaki xato emas — ma'lumot sizib chiqishi.

5. Hujumchi nigohi

«Hamma foydalanuvchiga bitta javob» bo'limidagi holat hujumchi uchun tayyor sovg'a — u hech narsa buzmaydi:

  1. Hujumchi biror foydalanuvchi so'rovidan keyin 60 soniya ichida o'sha URL'ni o'zi so'raydi.
  2. Kesh unga birovning javobini beradi: vazifalar, email, balans — nima keshlangan bo'lsa.

Teskari holat ham bor — kesh zaharlash (cache poisoning): hujumchi birinchi bo'lib so'rov yuboradi (masalan, g'alati sarlavha bilan), uning javobi keshga tushadi va hamma oladi.

Himoya:

  • Shaxsiy ma'lumotli marshrutda CacheInterceptor ishlatmang — yoki trackBy ni qayta yozib, kalitga foydalanuvchi ID sini qo'shing (CacheInterceptor dan meros olib). Biz bu variantni sinamadik.
  • Kesh kalitini egasi bilan quring — kanondagi KeshliOmbor kabi: kalitda vz:<egasiId>:….
  • HTTP darajasida Cache-Control: private (HTTP caching) — kanon javoblarida bor; bu brauzer va CDN uchun, server keshi uchun emas.

6. Kanon qarori: KeshliOmbor qoladi

27-qismdagi kesh boshqa joyda turadi — ombor qatlamida (Repository naqshi darsidagi o'ram):

flowchart LR
  subgraph A["CacheInterceptor"]
    R1["so'rov"] --> K1["kalit = URL"]
    K1 --> H1["handler"]
  end
  subgraph B["KeshliOmbor (kanon)"]
    X["VazifalarService"] --> K2["kalit = egasi + avlod + so'rov"]
    K2 --> P["PgOmbori / PrismaOmbori"]
  end

Chapda — HTTP qatlamida, URL bo'yicha. O'ngda — ombor qatlamida, egasi va avlod bo'yicha. KeshliOmbor har egasi uchun vz:<egasi>:avlod hisoblagichini saqlaydi va har o'qish kalitiga qo'shadi. Har yozuvda (yarat, yangila, ochir) — INCR: avlod oshdi, shu egasining hamma eski kalitlari birdan o'qilmay qoladi. Ularni qidirish va o'chirish shart emas — TTL o'zi tozalaydi.

CacheInterceptor KeshliOmbor (kanon)
Kalit URL egasi + avlod + so'rov
Yozuvdan keyin eskirgan, TTL gacha darhol yangi (avlod +1)
Invalidatsiya har URL ni del bitta INCR
Foydalanuvchilar aralashadi ajratilgan
Kod 2 dekorator ~90 qatorli klass (27-qism)

Nima yo'qotiladi: qulaylik. CacheInterceptor — ikki qator, KeshliOmbor — alohida klass, testlar, Redis ulanishini boshqarish. Lekin vazifalar-api da yozuvlar ko'p (vazifa belgilash — eng tez-tez amal) va ma'lumot shaxsiy. Bunday API uchun URL bo'yicha kesh noto'g'ri tanlov. Kanon tajribasining xulosasi ham shu (kanon o'lchovi, IlmHamroh, 2026-10).

CacheInterceptor qachon o'rinli? Ma'lumot ommaviy (hamma uchun bir xil) va kam o'zgaradi: valyuta kurslari, kurs katalogi, ob-havo. U yerda bir necha soniya eskirish muammo emas.

7. Ko'p uchraydigan xatolar

Belgi Sabab Davosi
Kesh deyarli ishlamaydi ttl: 60 — millisekund 60_000
Yozuvdan keyin eski ro'yxat URL kalit, invalidatsiya yo'q del yoki avlod kaliti
Lokalda yangi, prodakshnda eski xotira ombori havolani saqlaydi handler nusxa qaytarsin; testda ham Redis
Boshqa foydalanuvchi ma'lumoti kalitda foydalanuvchi yo'q shaxsiy marshrutda keshlamang yoki trackBy
Ikki ilova kalitlari to'qnashdi Redis kalitlari prefikssiz Keyv namespace yoki alohida baza
npm i cache-manager@7.2.10 — ETARGET versiya olib tashlangan npm view cache-manager versions

Oxirgi qator — kanon tajribasida uchragan haqiqiy holat: npm view cache-manager time da 7.2.10 bor edi, lekin versions ro'yxatida yo'q (nashrdan olib tashlangan) — o'rnatish yiqildi. Versiya tanlashda time emas, versions ga qarang.

8. Mashqlar

Mashqlar kurs/mashqlar/30/38-cachemodule/ da.

1-mashq (oson): kalit va birlik

To'ldiring:

  • CacheInterceptor kaliti — so'rovning i.
  • ttl: 60_000 — 60
  • Kesh xizmatini olish tokeni — @Inject( )
  • Kanondagi yozuvdan keyingi invalidatsiya — Redis'da bitta
Yechim
  • URL — query bilan birga.
  • soniya — 60_000 millisekund.
  • CACHE_MANAGER — @nestjs/cache-manager tokeni.
  • INCR — avlod hisoblagichi oshadi, eski kalitlar o'qilmaydi.

2-mashq (o'rta): URL keshi modeli

Brauzerda ishlaydigan urlKeshi(handler) yozing: ol(url) — Map da bo'lsa qaytaradi, bo'lmasa handler(url) ni chaqiradi va JSON nusxasini saqlaydi (Redis kabi); del(url). Sinov: kanon tajribasining 1–5 qadamlarini takrorlang va har qadamdan keyin javobdagi vazifalar sonini va handler necha marta chaqirilganini chiqaring. Ishora: JSON.parse(JSON.stringify(x)) (JSON asoslari).

Yechim
js
function urlKeshi(handler) {
  const kesh = new Map();
  return {
    ol(url) {
      if (!kesh.has(url)) kesh.set(url, JSON.stringify(handler(url)));
      return JSON.parse(kesh.get(url));
    },
    del(url) { kesh.delete(url); },
  };
}

const vazifalar = [{ id: 1, matn: "Non" }];
let chaqiruv = 0;
const k = urlKeshi(() => {
  chaqiruv++;
  return { vazifalar };
});
const son = (url) => k.ol(url).vazifalar.length;

console.log(`1) /v: ${son("/v")}, handler: ${chaqiruv}`);
console.log(`2) /v: ${son("/v")}, handler: ${chaqiruv}`);
console.log(`3) /v?x=1: ${son("/v?x=1")}, handler: ${chaqiruv}`);
vazifalar.push({ id: 2, matn: "Sut" });
console.log(`4) /v: ${son("/v")} (eskirgan)`);
vazifalar.push({ id: 3, matn: "Olma" });
k.del("/v");
console.log(`5) /v: ${son("/v")}, /v?x=1: ${son("/v?x=1")}`);

Konsolda:

text
1) /v: 1, handler: 1
2) /v: 1, handler: 1
3) /v?x=1: 1, handler: 2
4) /v: 1 (eskirgan)
5) /v: 3, /v?x=1: 1

Model kanon (Redis) natijasini takrorladi — chunki JSON.stringify havolani uzdi. JSON.stringify ni olib tashlab, obyektning o'zini saqlab ko'ring: 4-qadamda 2 chiqadi — «Xotira ombori havolani saqlaydi» bo'limidagi holat.

3-mashq (qiyin): avlod kalitli kesh

avlodKeshi(ombor) yozing — KeshliOmbor g'oyasi. royxat(egasi, sorov) kaliti: vz:${egasi}:${avlod}:${sorov}; yarat(egasi, matn) — omborga yozadi va faqat shu egasining avlodini oshiradi. Ombor — { egasi: [matnlar] } obyekt, o'qishlar sanaladi. Sinov: Ali ikki marta o'qiydi, Malika bir marta, Ali yozadi, ikkalasi yana o'qiydi. Ishora: avlodlar uchun alohida Map, sukut 1.

Yechim
js
function avlodKeshi(ombor) {
  const kesh = new Map();
  const avlod = new Map();
  let oqish = 0;
  const av = (egasi) => avlod.get(egasi) ?? 1;
  return {
    royxat(egasi, sorov) {
      const kalit = `vz:${egasi}:${av(egasi)}:${sorov}`;
      if (!kesh.has(kalit)) {
        oqish++;
        kesh.set(kalit, JSON.stringify(ombor[egasi] ?? []));
      }
      return JSON.parse(kesh.get(kalit));
    },
    yarat(egasi, matn) {
      (ombor[egasi] ??= []).push(matn);
      avlod.set(egasi, av(egasi) + 1); // INCR
    },
    get oqish() { return oqish; },
  };
}

const k = avlodKeshi({ ali: ["Non"], malika: ["Kitob"] });
k.royxat("ali", "?limit=10");
k.royxat("ali", "?limit=10");
console.log("Malika:", k.royxat("malika", "?limit=10"));
console.log("o'qish:", k.oqish);
k.yarat("ali", "Sut");
console.log("Ali:", k.royxat("ali", "?limit=10"));
console.log("Malika:", k.royxat("malika", "?limit=10"));
console.log("o'qish:", k.oqish);

Konsolda:

text
Malika: [ 'Kitob' ]
o'qish: 2
Ali: [ 'Non', 'Sut' ]
Malika: [ 'Kitob' ]
o'qish: 3

Ikki marta o'qigan Ali — bitta ombor o'qishi, Malika — o'zi alohida (jami 2). Ali yozgach, uning avlodi 2 bo'ldi: yangi ro'yxat darhol ko'rindi (3-o'qish). Malika'ning keshi tegilmadi — uning avlodi o'zgarmagan. CacheInterceptor dagi uch muammo — eskirish, aralashuv, kalitlarni qidirish — bu yerda yo'q. Kanondagi KeshliOmbor xuddi shu, faqat Redis'da (INCR, TTL bilan).

9. Loyiha qadami: o'zgarish yo'q — va nega

vazifalar-api o'zgarmaydi: kesh 27-qismdan beri KeshliOmbor da (REDIS_URL berilsa, OmborModule uni Postgres/Prisma ombori ustiga o'raydi). CacheModule kanon tajribasida sinaldi va loyihaga kirmadi — «Kanon qarori» bo'limidagi jadval sabablari bilan.

O'z loyihangizda kichik tekshiruv: REDIS_URL bilan ishga tushiring, GET /v1/vazifalar ni ikki marta so'rang, keyin PATCH bilan bitta vazifani belgilang va yana GET. Ro'yxat darhol yangi bo'lishi kerak — avlod kaliti ishladi. Redis'da (redis-cli KEYS 'vz:*') vz:1:avlod kalitini ko'rasiz.

10. Real ishda

  • CacheModule — Nest loyihalarida ommaviy, kam o'zgaradigan ma'lumot uchun keng ishlatiladi: sozlamalar, kataloglar, tashqi API javoblari.
  • Kesh tufayli ma'lumot sizishi — haqiqiy hodisalarning tanish sababi: shaxsiy sahifa umumiy kalit bilan keshlangan. Review'da "bu marshrut foydalanuvchiga bog'liqmi?" savoli majburiy.
  • TTL birligi — eski maqolalarda ttl soniyada yozilgan misollar uchraydi; ko'chirishdan oldin o'rnatilgan versiya hujjatini tekshiring. Hozirgi cache-manager 7 da — millisekund.
  • Intervyu: "Nest'da keshni qanday qilasiz?", "CacheInterceptor kaliti nima?", "invalidatsiyani qanday hal qilasiz?".

Xulosa

  • CacheModule.register/registerAsync + Keyv omborlari (xotira yoki @keyv/redis); TTL — millisekund.
  • @Inject(CACHE_MANAGER) — qo'lda get/set/del (cache-aside).
  • CacheInterceptor — GET javobi, kalit = URL; yozuvdan keyin eskiradi, invalidatsiya — har URL qo'lda.
  • Xotira ombori havolani saqlaydi — lokal natija Redis'dagidan farq qilishi mumkin.
  • URL kaliti foydalanuvchini bilmaydi — shaxsiy ma'lumot sizadi.
  • Kanon: ombor qatlamidagi KeshliOmbor — egasi + avlod kaliti, yozuvda bitta INCR.

Keyingi dars: Rejalashtirish: @nestjs/schedule — vaqt bo'yicha ishlarni (cron, interval) Nest ichida bajaramiz.

Manbalar

Ulashish:Telegram'da

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
NestJS keshlash: CacheModule, CacheInterceptor va Redis (Keyv) — IlmHamroh