Payload CMS Cache Strategy Redis — คู่มือฉบับสมบูรณ์ 2026 | SiamCafe Blog

Payload CMS Cache Strategy Redis — คู่มือฉบับสมบูรณ์ 2026 | SiamCafe Blog

Payload CMS Cache Strategy Redis — คู่มือฉบับสมบูรณ์ 2026 | SiamCafe Blog

ในโลกของการพัฒนาเว็บที่ขับเคลื่อนด้วยข้อมูลในปัจจุบัน ประสิทธิภาพและความสามารถในการปรับขนาดได้เป็นสิ่งสำคัญยิ่งสำหรับความสำเร็จของแอปพลิเคชัน ไม่ว่าจะเป็นเว็บไซต์ข่าวที่มีผู้เข้าชมจำนวนมาก แพลตฟอร์มอีคอมเมิร์ซที่ซับซ้อน หรือแอปพลิเคชันองค์กรที่มีข้อมูลจำนวนมหาศาล ความสามารถในการส่งมอบข้อมูลให้กับผู้ใช้ได้อย่างรวดเร็วและมีประสิทธิภาพคือปัจจัยสำคัญที่สร้างความแตกต่าง

Payload CMS ซึ่งเป็น Headless CMS ที่สร้างขึ้นด้วย TypeScript และ Node.js ได้รับความนิยมอย่างรวดเร็วจากนักพัฒนาเนื่องจากมีความยืดหยุ่น ประสิทธิภาพ และประสบการณ์การพัฒนาที่ยอดเยี่ยม อย่างไรก็ตาม แม้ว่า Payload จะมีประสิทธิภาพโดยเนื้อแท้ แต่เมื่อแอปพลิเคชันเติบโตขึ้นและปริมาณข้อมูลเพิ่มขึ้น การดึงข้อมูลจากฐานข้อมูลโดยตรงทุกครั้งอาจกลายเป็นคอขวดได้ นี่คือจุดที่กลยุทธ์การแคชเข้ามามีบทบาทสำคัญ และเมื่อพูดถึงการแคชที่มีประสิทธิภาพและรวดเร็ว Redis ก็เป็นหนึ่งในตัวเลือกอันดับต้นๆ ที่นักพัฒนาทั่วโลกไว้วางใจ

บทความฉบับสมบูรณ์นี้จะเจาะลึกถึงการผสานรวม Payload CMS เข้ากับ Redis เพื่อสร้างกลยุทธ์การแคชที่แข็งแกร่งและมีประสิทธิภาพ เราจะสำรวจตั้งแต่พื้นฐานของการแคช ประโยชน์ของการใช้ Redis ไปจนถึงการใช้งานจริง กลยุทธ์การแคชที่หลากหลาย และแนวทางปฏิบัติที่ดีที่สุด เพื่อให้คุณสามารถสร้างแอปพลิเคชันที่รวดเร็ว ตอบสนองได้ดี และปรับขนาดได้สำหรับปี 2026 และในอนาคต

ทำไมการแคชจึงสำคัญในยุคดิจิทัลปัจจุบัน?

ก่อนที่เราจะดำดิ่งสู่รายละเอียดทางเทคนิคของการผสานรวม Payload CMS กับ Redis เรามาทำความเข้าใจถึงแก่นแท้ของ “การแคช” และเหตุผลที่มันมีความสำคัญอย่างยิ่งในภูมิทัศน์ของเว็บที่เปลี่ยนแปลงไปอย่างรวดเร็ว

การแคชคืออะไร?

การแคชคือกระบวนการจัดเก็บสำเนาของข้อมูลที่เข้าถึงบ่อยในตำแหน่งที่เข้าถึงได้เร็วกว่า (แคช) เมื่อมีการร้องขอข้อมูลเดิมอีกครั้ง ระบบสามารถดึงข้อมูลจากแคชได้ทันที แทนที่จะต้องไปดึงจากแหล่งข้อมูลหลัก (เช่น ฐานข้อมูล) ซึ่งมักจะช้ากว่า

ประโยชน์หลักของการแคช

การนำกลยุทธ์การแคชมาใช้มอบประโยชน์มากมายให้กับแอปพลิเคชันของคุณ:

  • ปรับปรุงเวลาตอบสนอง (Improved Response Times): นี่คือประโยชน์ที่ชัดเจนที่สุด การดึงข้อมูลจากหน่วยความจำที่รวดเร็วของแคชนั้นเร็วกว่าการสอบถามฐานข้อมูลที่เกี่ยวข้องกับ I/O และการประมวลผล การลดเวลาในการโหลดหน้าเว็บหรือ API response ส่งผลให้ผู้ใช้ได้รับประสบการณ์ที่ดีขึ้นอย่างมาก
  • ลดภาระของฐานข้อมูล (Reduced Database Load): ทุกครั้งที่มีการดึงข้อมูลจากแคช หมายความว่าฐานข้อมูลไม่ต้องทำงานเพื่อตอบสนองคำขอนั้น การลดจำนวนการสอบถามฐานข้อมูลโดยตรงช่วยลดภาระงานของฐานข้อมูล ทำให้ฐานข้อมูลมีทรัพยากรมากขึ้นในการจัดการกับการเขียนข้อมูลหรือการสอบถามที่ซับซ้อนอื่นๆ
  • เพิ่มความสามารถในการปรับขนาด (Enhanced Scalability): เมื่อฐานข้อมูลมีภาระงานน้อยลง แอปพลิเคชันของคุณสามารถรองรับผู้ใช้และคำขอได้มากขึ้นโดยไม่ต้องเพิ่มทรัพยากรฐานข้อมูลอย่างรวดเร็ว การแคชช่วยให้คุณสามารถปรับขนาดแอปพลิเคชันในแนวนอนได้ง่ายขึ้น
  • ประหยัดค่าใช้จ่าย (Cost Savings): การลดภาระของฐานข้อมูลอาจหมายถึงความต้องการเซิร์ฟเวอร์ฐานข้อมูลที่มีประสิทธิภาพสูงน้อยลง หรือสามารถใช้ Instance ที่เล็กลงได้ ซึ่งนำไปสู่การประหยัดค่าใช้จ่ายด้านโครงสร้างพื้นฐาน
  • ประสบการณ์ผู้ใช้ที่ดีขึ้น (Better User Experience – UX): เว็บไซต์หรือแอปพลิเคชันที่รวดเร็วทำให้ผู้ใช้พึงพอใจมากขึ้น ลดอัตราการตีกลับ (bounce rate) และเพิ่มการมีส่วนร่วม (engagement)

ความท้าทายของการแคช

แม้ว่าการแคชจะมีประโยชน์มหาศาล แต่ก็มาพร้อมกับความท้าทายบางประการ โดยเฉพาะอย่างยิ่งปัญหาเรื่อง “ข้อมูลเก่า” (Stale Data) หรือ “Cache Invalidation” การจัดการกับการทำให้แคชเป็นโมฆะอย่างมีประสิทธิภาพเมื่อข้อมูลต้นฉบับมีการเปลี่ยนแปลงเป็นสิ่งสำคัญ เพื่อให้แน่ใจว่าผู้ใช้จะได้รับข้อมูลที่ถูกต้องและเป็นปัจจุบัน บทความนี้จะกล่าวถึงกลยุทธ์ในการจัดการกับความท้าทายเหล่านี้

ทำความเข้าใจ Payload CMS และกลไกการดึงข้อมูล

Payload CMS เป็น Headless CMS ที่ทันสมัย สร้างขึ้นบน Node.js และ React ทำให้เป็นตัวเลือกที่ยอดเยี่ยมสำหรับการสร้างแอปพลิเคชันที่ปรับแต่งได้และมีประสิทธิภาพ ด้วยการเน้นที่ TypeScript และ GraphQL (หรือ REST API) Payload มอบประสบการณ์การพัฒนาที่ราบรื่นและมีประสิทธิภาพ

โครงสร้างข้อมูลและ API ของ Payload CMS

Payload CMS จัดเก็บข้อมูลใน MongoDB เป็นค่าเริ่มต้น (แต่สามารถขยายไปยังฐานข้อมูลอื่น ๆ ได้) และเปิดเผยข้อมูลผ่าน REST API หรือ GraphQL API ที่สร้างขึ้นโดยอัตโนมัติสำหรับ Collection และ Global ของคุณ นักพัฒนาสามารถกำหนด Collection และ Global ได้อย่างอิสระ พร้อมทั้งกำหนด Field, Hooks และ Access Control ที่ซับซ้อนได้

เมื่อมีการร้องขอข้อมูล Payload จะทำการสอบถามฐานข้อมูล MongoDB เพื่อดึงข้อมูลที่เกี่ยวข้อง และส่งคืนผลลัพธ์ในรูปแบบ JSON การทำงานพื้นฐานนี้มีประสิทธิภาพสำหรับกรณีการใช้งานส่วนใหญ่ แต่เมื่อปริมาณการเข้าชมเพิ่มขึ้น การสอบถามฐานข้อมูลซ้ำ ๆ สำหรับข้อมูลเดียวกันอาจกลายเป็นปัญหาด้านประสิทธิภาพได้

Payload Hooks: หัวใจสำคัญของการผสานรวมการแคช

Payload CMS มีระบบ Hook ที่ทรงพลัง ซึ่งช่วยให้นักพัฒนาสามารถแทรกโค้ดที่กำหนดเองได้ในขั้นตอนต่างๆ ของวงจรชีวิตข้อมูล Hooks เหล่านี้เป็นเครื่องมือสำคัญที่เราจะใช้ในการผสานรวมกลยุทธ์การแคชกับ Redis

Hooks ที่เกี่ยวข้องกับการแคชได้แก่:

  • beforeRead: ทำงานก่อนที่ข้อมูลจะถูกอ่านจากฐานข้อมูล เหมาะสำหรับการตรวจสอบแคช
  • afterRead: ทำงานหลังจากที่ข้อมูลถูกอ่านจากฐานข้อมูล เหมาะสำหรับการจัดเก็บข้อมูลลงในแคช
  • beforeChange: ทำงานก่อนที่ข้อมูลจะถูกบันทึกลงในฐานข้อมูล เหมาะสำหรับการล้างแคชที่เกี่ยวข้อง
  • afterChange: ทำงานหลังจากที่ข้อมูลถูกบันทึกลงในฐานข้อมูล เหมาะสำหรับการล้างแคชหรืออัปเดตแคช
  • beforeDelete: ทำงานก่อนที่ข้อมูลจะถูกลบ เหมาะสำหรับการล้างแคชที่เกี่ยวข้อง
  • afterDelete: ทำงานหลังจากที่ข้อมูลถูกลบ เหมาะสำหรับการล้างแคชที่เกี่ยวข้อง

การใช้ Hooks เหล่านี้อย่างมีกลยุทธ์ เราสามารถสร้างเลเยอร์แคชที่ชาญฉลาดซึ่งทำงานร่วมกับ Payload CMS ได้อย่างราบรื่น

Redis: สุดยอดเครื่องมือแคชสำหรับแอปพลิเคชันสมัยใหม่

Redis (Remote Dictionary Server) เป็น In-memory Data Structure Store แบบโอเพนซอร์สที่ใช้เป็นฐานข้อมูล แคช และ Message Broker มันโดดเด่นด้วยความเร็วที่เหนือกว่า ความยืดหยุ่น และความสามารถในการรองรับโครงสร้างข้อมูลที่หลากหลาย ทำให้เป็นตัวเลือกที่ยอดเยี่ยมสำหรับการแคชในแอปพลิเคชันที่ต้องการประสิทธิภาพสูง

เหตุใดต้องเป็น Redis สำหรับการแคช?

เมื่อเปรียบเทียบกับโซลูชันการแคชอื่นๆ หรือการแคชในหน่วยความจำของแอปพลิเคชันโดยตรง Redis มีข้อได้เปรียบที่สำคัญหลายประการ:

  • ความเร็วที่เหนือกว่า (Blazing Fast Performance): Redis จัดเก็บข้อมูลในหน่วยความจำ RAM ทำให้สามารถอ่านและเขียนข้อมูลได้ในระดับไมโครวินาที ซึ่งเร็วกว่าการดึงข้อมูลจากฐานข้อมูลแบบดั้งเดิมอย่างมาก
  • รองรับโครงสร้างข้อมูลที่หลากหลาย (Rich Data Structures): Redis ไม่ใช่แค่ Key-Value Store ธรรมดา แต่รองรับโครงสร้างข้อมูลที่หลากหลาย เช่น Strings, Hashes, Lists, Sets, Sorted Sets, Bitmaps และ HyperLogLogs ความหลากหลายนี้ช่วยให้คุณสามารถแคชข้อมูลในรูปแบบที่เหมาะสมที่สุดสำหรับกรณีการใช้งานของคุณ เช่น การแคชออบเจกต์ JSON ทั้งหมด (ใช้ Strings), การแคชข้อมูลผู้ใช้ (ใช้ Hashes) หรือการแคชรายการที่เรียงลำดับ (ใช้ Sorted Sets)
  • ความคงทนของข้อมูล (Data Persistence): แม้ว่าจะเป็น In-memory Store แต่ Redis ก็มีความสามารถในการบันทึกข้อมูลลงดิสก์ (RDB snapshotting และ AOF logging) ซึ่งหมายความว่าข้อมูลในแคชของคุณจะไม่หายไปเมื่อเซิร์ฟเวอร์ Redis รีสตาร์ท (แม้ว่าสำหรับแคชบริสุทธิ์ การสูญเสียข้อมูลแคชอาจไม่ใช่ปัญหาใหญ่เสมอไป)
  • คุณสมบัติขั้นสูง (Advanced Features):
    • TTL (Time-to-Live): สามารถกำหนดเวลาหมดอายุสำหรับ Key ได้โดยอัตโนมัติ ซึ่งเป็นสิ่งสำคัญสำหรับการจัดการข้อมูลเก่าในแคช
    • Pub/Sub (Publish/Subscribe): ระบบการส่งข้อความแบบเรียลไทม์ที่สามารถนำมาใช้สำหรับการแจ้งเตือนการทำให้แคชเป็นโมฆะแบบกระจาย (Distributed Cache Invalidation)
    • Transactions: สามารถรันชุดคำสั่ง Redis เป็น Atomic Operation ได้
    • Scripting (Lua): สามารถรันสคริปต์ Lua เพื่อดำเนินการที่ซับซ้อนบนเซิร์ฟเวอร์ Redis ได้
  • ความพร้อมใช้งานสูงและปรับขนาดได้ (High Availability & Scalability): Redis รองรับ Master-Replica Replication และ Redis Cluster สำหรับการปรับขนาดในแนวนอนและความพร้อมใช้งานสูง

Redis เทียบกับ Memcached

เมื่อพูดถึง In-memory Cache, Memcached มักจะถูกนำมาเปรียบเทียบกับ Redis นี่คือตารางเปรียบเทียบสั้นๆ:

คุณสมบัติ Redis Memcached
ประเภท Data Structure Store (Cache, DB, Message Broker) In-memory Cache System
โครงสร้างข้อมูล Strings, Hashes, Lists, Sets, Sorted Sets, Bitmaps, Geospatial, Streams Strings (Key-Value) เท่านั้น
ความคงทนของข้อมูล รองรับ (RDB, AOF) ไม่รองรับ (ข้อมูลหายเมื่อรีสตาร์ท)
คุณสมบัติขั้นสูง TTL, Pub/Sub, Transactions, Lua Scripting, Replication, Clustering TTL พื้นฐาน
การใช้งาน Caching, Session Store, Leaderboards, Real-time Analytics, Message Queue Caching ที่เรียบง่าย
ความซับซ้อน ซับซ้อนกว่าเล็กน้อยเนื่องจากคุณสมบัติที่หลากหลาย เรียบง่ายกว่า

สำหรับแอปพลิเคชันสมัยใหม่ที่ต้องการความยืดหยุ่น ประสิทธิภาพ และคุณสมบัติที่หลากหลาย Redis มักจะเป็นตัวเลือกที่เหนือกว่า Memcached

การติดตั้งและกำหนดค่า Redis สำหรับ Payload CMS

ก่อนที่เราจะเริ่มเขียนโค้ดสำหรับการแคช เราต้องแน่ใจว่า Redis Server ของเราพร้อมใช้งาน

การติดตั้ง Redis

คุณสามารถติดตั้ง Redis ได้หลายวิธี:

  1. ผ่าน Package Manager (Linux/macOS):
    # สำหรับ Ubuntu/Debian
    sudo apt update
    sudo apt install redis-server
    
    # สำหรับ macOS (Homebrew)
    brew install redis
  2. ผ่าน Docker (แนะนำสำหรับการพัฒนา):
    docker run --name my-redis -p 6379:6379 -d redis

    คำสั่งนี้จะรัน Redis Server ใน Docker container และ map พอร์ต 6379 ของ container ไปยังพอร์ต 6379 ของเครื่องโฮสต์ของคุณ

  3. บริการคลาวด์ (สำหรับ Production):

    สำหรับ Production คุณควรพิจารณาใช้บริการ Redis ที่จัดการโดยผู้ให้บริการคลาวด์ เช่น AWS ElastiCache, Google Cloud Memorystore หรือ Azure Cache for Redis ซึ่งจะดูแลเรื่องความพร้อมใช้งาน การสำรองข้อมูล และการปรับขนาดให้คุณ

การกำหนดค่า Redis (พื้นฐาน)

ไฟล์กำหนดค่าหลักของ Redis คือ redis.conf (มักจะอยู่ที่ /etc/redis/redis.conf บน Linux) คุณอาจต้องการปรับเปลี่ยนการตั้งค่าบางอย่าง:

  • port 6379: พอร์ตที่ Redis รับการเชื่อมต่อ
  • bind 127.0.0.1: กำหนดว่า Redis จะฟังการเชื่อมต่อจาก IP ไหน (สำหรับ Production ควรระบุ IP ของเซิร์ฟเวอร์หรือ 0.0.0.0 ถ้าต้องการให้ฟังทุก IP แต่ต้องระวังเรื่องความปลอดภัย)
  • requirepass your_strong_password: ตั้งรหัสผ่านเพื่อเพิ่มความปลอดภัย (แนะนำอย่างยิ่งสำหรับ Production)
  • maxmemory <bytes>: กำหนดขีดจำกัดหน่วยความจำสำหรับ Redis เมื่อถึงขีดจำกัด Redis จะเริ่มลบ Key ตามนโยบายการลบข้อมูล (Eviction Policy) ที่กำหนด
  • maxmemory-policy noeviction: นโยบายการลบข้อมูลเมื่อหน่วยความจำเต็ม (เช่น allkeys-lru, volatile-lru)

การผสานรวม Redis Cache กับ Payload CMS ด้วยกลยุทธ์การแคช

ตอนนี้เรามาดูวิธีการผสานรวม Redis เข้ากับ Payload CMS เพื่อสร้างกลยุทธ์การแคชที่มีประสิทธิภาพ เราจะใช้ไลบรารี ioredis ซึ่งเป็น Redis client ที่ได้รับความนิยมและมีประสิทธิภาพสำหรับ Node.js

ขั้นตอนที่ 1: ติดตั้ง Redis Client

ในโปรเจกต์ Payload ของคุณ ให้ติดตั้ง ioredis:

npm install ioredis
# หรือ
yarn add ioredis

ขั้นตอนที่ 2: สร้าง Instance ของ Redis Client

คุณควรสร้าง Redis client instance เพียงครั้งเดียวและนำกลับมาใช้ใหม่ตลอดทั้งแอปพลิเคชัน เพื่อหลีกเลี่ยง overhead ในการสร้างการเชื่อมต่อใหม่ทุกครั้ง

สร้างไฟล์ src/redis.ts (หรือ src/redis.js):

// src/redis.ts
import Redis from 'ioredis';

const redisClient = new Redis({
  port: parseInt(process.env.REDIS_PORT || '6379', 10),
  host: process.env.REDIS_HOST || '127.0.0.1',
  password: process.env.REDIS_PASSWORD,
  db: parseInt(process.env.REDIS_DB || '0', 10),
  maxRetriesPerRequest: null, // Disable retries for some commands if needed
});

redisClient.on('connect', () => {
  console.log('Connected to Redis!');
});

redisClient.on('error', (err) => {
  console.error('Redis Error:', err);
});

export default redisClient;

อย่าลืมกำหนดค่าตัวแปรสภาพแวดล้อม (Environment Variables) ในไฟล์ .env ของคุณ:

REDIS_HOST=127.0.0.1
REDIS_PORT=6379
REDIS_PASSWORD=your_strong_password # ถ้ามี
REDIS_DB=0

ขั้นตอนที่ 3: การนำกลยุทธ์การแคชไปใช้ด้วย Payload Hooks

เราจะเน้นไปที่กลยุทธ์หลักสองสามอย่าง:

  1. Read-Through/Cache-Aside: ตรวจสอบแคชก่อน ถ้ามี ให้ส่งคืนจากแคช ถ้าไม่มี ให้ดึงจาก DB, จัดเก็บในแคช แล้วส่งคืน
  2. Cache Invalidation: ทำให้แคชเป็นโมฆะเมื่อข้อมูลต้นฉบับมีการเปลี่ยนแปลง (สร้าง/อัปเดต/ลบ)

กลยุทธ์ที่ 1: Read-Through Cache สำหรับการอ่านข้อมูล

กลยุทธ์นี้เหมาะสำหรับการอ่านข้อมูลจาก Collection ต่างๆ เราจะใช้ beforeRead และ afterRead hooks ใน Payload

สมมติว่าเรามี Collection ชื่อ Posts และต้องการแคชแต่ละโพสต์

ในไฟล์ src/collections/Posts.ts:

// src/collections/Posts.ts
import { CollectionConfig } from 'payload/types';
import redisClient from '../redis';

const Posts: CollectionConfig = {
  slug: 'posts',
  admin: {
    use           : 'Posts',
  },
  access: {
    read: () => true, // กำหนดสิทธิ์การอ่านตามต้องการ
  },
  fields: [
    {
      name: 'title',
      type: 'text',
      required: true,
    },
    {
      name: 'content',
      type: 'richText',
    },
    {
      name: 'slug',
      type: 'text',
      unique: true,
    },
    // ... อื่นๆ
  ],
  hooks: {
    beforeRead: [
      async ({ doc, req, query }) => {
        // ตรวจสอบว่าเป็นการอ่านเอกสารเดี่ยว (by ID หรือ by Slug)
        if (doc || (query && (query.id || query.slug))) {
          const docId = doc ? doc.id : (query.id || query.slug); // ใช้ ID หรือ Slug เป็นตัวระบุ
          const cacheKey = `payload:posts:${docId}`;
          
          try {
            const cachedPost = await redisClient.get(cacheKey);
            if (cachedPost) {
              console.log(`Cache hit for post: ${docId}`);
              return JSON.parse(cachedPost); // ส่งคืนข้อมูลจากแคช
            }
          } catch (error) {
            console.error(`Error fetching from cache for ${cacheKey}:`, error);
            // ดำเนินการต่อไปเพื่อดึงจาก DB หากแคชล้มเหลว
          }
        }
        return doc; // หากไม่มีในแคช หรือไม่ใช่การอ่านเอกสารเดี่ยว ให้ดำเนินการต่อ
      },
    ],
    afterRead: [
      async ({ doc, req }) => {
        if (doc) { // ตรวจสอบว่ามีเอกสารจริง
          const cacheKey = `payload:posts:${doc.id}`;
          const cacheTTL = 60 * 60; // แคช 1 ชั่วโมง (เป็นวินาที)

          try {
            await redisClient.setex(cacheKey, cacheTTL, JSON.stringify(doc));
            console.log(`Cache set for post: ${doc.id}`);
          } catch (error) {
            console.error(`Error setting cache for ${cacheKey}:`, error);
          }
        }
        return doc;
      },
    ],
    // ... Hooks สำหรับการ Invalidation จะกล่าวถึงในหัวข้อถัดไป
  },
};

export default Posts;

คำอธิบาย:

  • beforeRead: ก่อนที่ Payload จะดึงข้อมูลจาก MongoDB เราจะตรวจสอบ Redis ด้วย cacheKey ที่สร้างจาก ID ของโพสต์ หากพบข้อมูลในแคช เราจะส่งคืนข้อมูลนั้นทันที และ Payload จะไม่ทำการสอบถามฐานข้อมูล
  • afterRead: หลังจากที่ Payload ดึงข้อมูลจาก MongoDB (และไม่มีในแคช) เราจะจัดเก็บข้อมูลที่ได้มาลงใน Redis ด้วย setex ซึ่งจะกำหนด TTL (Time-to-Live) ให้กับ Key นั้น เพื่อให้ข้อมูลหมดอายุโดยอัตโนมัติหลังจากเวลาที่กำหนด

กลยุทธ์ที่ 2: Cache Invalidation (การล้างแคช)

การล้างแคชเมื่อข้อมูลมีการเปลี่ยนแปลงเป็นสิ่งสำคัญเพื่อให้มั่นใจว่าผู้ใช้จะได้รับข้อมูลที่ทันสมัย เราจะใช้ afterChange และ afterDelete hooks

ในไฟล์ src/collections/Posts.ts (ต่อจากโค้ดเดิม):

// src/collections/Posts.ts (ต่อจากโค้ดเดิม)
// ... (โค้ดก่อนหน้าสำหรับ beforeRead, afterRead)

// เพิ่ม Hooks สำหรับการ Invalidation
hooks: {
    // ... (beforeRead, afterRead)
    afterChange: [
      async ({ doc, req, operation }) => {
        if (doc) {
          const cacheKey = `payload:posts:${doc.id}`;
          try {
            await redisClient.del(cacheKey); // ลบแคชของโพสต์ที่เปลี่ยนแปลง
            console.log(`Cache invalidated for post: ${doc.id} after ${operation}`);

            // ลบแคชของรายการโพสต์ทั้งหมดด้วย (ถ้าคุณแคชรายการทั้งหมด)
            await redisClient.del('payload:posts:all'); // สมมติว่ามีแคชสำหรับโพสต์ทั้งหมด
            console.log(`Cache invalidated for all posts list.`);

          } catch (error) {
            console.error(`Error invalidating cache for ${cacheKey}:`, error);
          }
        }
        return doc;
      },
    ],
    afterDelete: [
      async ({ id, req }) => {
        const cacheKey = `payload:posts:${id}`;
        try {
          await redisClient.del(cacheKey); // ลบแคชของโพสต์ที่ถูกลบ
          console.log(`Cache invalidated for deleted post: ${id}`);

          // ลบแคชของรายการโพสต์ทั้งหมดด้วย
          await redisClient.del('payload:posts:all');
          console.log(`Cache invalidated for all posts list.`);

        } catch (error) {
          console.error(`Error invalidating cache for deleted post ${id}:`, error);
        }
      },
    ],
  },
};

export default Posts;

คำอธิบาย:

  • afterChange: หลังจากที่โพสต์ถูกสร้างหรืออัปเดต เราจะลบ Key ของแคชที่เกี่ยวข้องกับโพสต์นั้นออกจาก Redis เพื่อให้แน่ใจว่าการร้องขอครั้งต่อไปจะดึงข้อมูลที่อัปเดตจากฐานข้อมูล
  • afterDelete: หลังจากที่โพสต์ถูกลบ เราจะลบ Key ของแคชที่เกี่ยวข้องกับโพสต์นั้นออกเช่นกัน
  • นอกจากนี้ เรายังแนะนำแนวคิดของการลบแคชของ “รายการทั้งหมด” (เช่น payload:posts:all) ซึ่งจำเป็นหากคุณมีการแคชผลลัพธ์ของการดึงข้อมูลรายการทั้งหมดของ Collection

การแคชผลลัพธ์การค้นหา (List Caching)

นอกจากการแคชเอกสารเดี่ยวแล้ว การแคชผลลัพธ์การค้นหา (เช่น รายการโพสต์ทั้งหมด, โพสต์ตามหมวดหมู่) ก็เป็นสิ่งสำคัญ

คุณสามารถทำได้โดยการสร้าง Custom Endpoint ใน Payload หรือใช้ Global hook เพื่อแคชผลลัพธ์ของการสอบถามที่มีตัวกรอง/การเรียงลำดับที่แตกต่างกัน

ตัวอย่างการแคชรายการโพสต์ทั้งหมด (โดยใช้ Custom Endpoint):

ในไฟล์ src/payload.config.ts หรือไฟล์ที่เกี่ยวข้องกับการกำหนดค่า API:

// src/payload.config.ts (หรือในไฟล์ที่แยกต่างหากสำหรับ API)
import { buildConfig } from 'payload/config';
import redisClient from './redis'; // ตรวจสอบเส้นทางที่ถูกต้อง

export default buildConfig({
  // ... การกำหนดค่าอื่นๆ
  endpoints: [
    {
      path: '/posts/cached',
      method: 'get',
      handler: async (req, res, next) => {
        const cacheKey = 'payload:posts:all';
        const cacheTTL = 60 * 5; // แคช 5 นาที

        try {
          const cachedPosts = await redisClient.get(cacheKey);
          if (cachedPosts) {
            console.log('Cache hit for all posts list.');
            return res.status(200).json(JSON.parse(cachedPosts));
          }

          // ถ้าไม่มีในแคช ให้ดึงจาก Payload API โดยตรง
          const posts = await req.payload.find({
            collection: 'posts',
            limit: 100, // หรือตามต้องการ
            sort: '-createdAt',
          });

          await redisClient.setex(cacheKey, cacheTTL, JSON.stringify(posts.docs));
          console.log('Cache set for all posts list.');
          return res.status(200).json(posts.docs);

        } catch (error) {
          console.error('Error fetching/caching all posts:', error);
          return res.status(500).json({ error: 'Internal Server Error' });
        }
      },
    },
  ],
  // ...
});

คำอธิบาย:

  • เราสร้าง Custom Endpoint /posts/cached ที่จะทำหน้าที่เป็น Cache-Aside สำหรับรายการโพสต์ทั้งหมด
  • เมื่อมีการเรียก Endpoint นี้ มันจะตรวจสอบ Redis ก่อน หากพบ จะส่งคืนข้อมูลจากแคช
  • หากไม่พบ จะทำการสอบถาม Payload API (ซึ่งจะไปดึงจาก DB) จัดเก็บผลลัพธ์ลงใน Redis แล้วส่งคืน
  • ใน afterChange และ afterDelete hooks ของ Collection Posts เราจะต้องลบ payload:posts:all Key เพื่อให้แคชของรายการทั้งหมดเป็นโมฆะเมื่อมีการเปลี่ยนแปลงข้อมูล

บทความที่เกี่ยวข้อง

จัดส่งรวดเร็วส่งด่วนทั่วประเทศ
รับประกันสินค้าเคลมง่าย มีใบรับประกัน
ผ่อนชำระได้บัตรเครดิต 0% สูงสุด 10 เดือน
สะสมแต้ม รับส่วนลดส่วนลดและคะแนนสะสม

© 2026 SiamLancard — จำหน่ายการ์ดแลน อุปกรณ์ Server และเครื่องพิมพ์ใบเสร็จ

SiamLancard
Logo
Free Forex EA — XM Signal · SiamCafe Blog · SiamLancard · Siam2R · iCafeFX
iCafeForex.com - สอนเทรด Forex | SiamCafe.net
Shopping cart