สรุปรายการทดสอบสำหรับ POC Custom Cache Handler with Redis แบ่งตาม Router และ Concern ที่ต้องระวัง
| Route Type | Path | Cache Type | Revalidate | Expected Behavior |
|---|---|---|---|---|
| App Router - Page | /app-isr |
Page Cache | 300s | Cache HIT after first load |
| App Router - Page | /app-ssg |
Static | Build time | Always cached |
| App Router - API | /api/cached-fetch |
Data Cache | 60s | Fast response after first call |
| App Router - API | /api/real-time |
None | force-dynamic | Always fresh (slow) |
| App Router - Image | /gallery |
Image Cache | 300s | Images load instantly after first view |
| Pages Router - Page | /page-static |
Page Cache | 60s | Cache HIT after first load |
| Pages Router - SSR | /page-server |
None | SSR | Always fresh |
| Pages Router - API | N/A | None | N/A | Never cached |
Concern: ต้องรองรับ Time-based revalidation
Steps:
- เปิด
/app-isrครั้งแรก → จดเวลาที่ generate - Refresh หน้าซ้ำภายใน 300 วินาที → เวลาที่ generate ต้องเหมือนเดิม (Cache HIT)
- รอ 300+ วินาที → Refresh → เวลาที่ generate ต้องเปลี่ยน (Revalidated)
- เช็ค Network tab → Response time ต้อง < 50ms (ถ้า cached)
Expected Results:
- ✅ First request: ~200-500ms (MISS)
- ✅ Within 300s: < 50ms (HIT)
- ✅ After 300s: ~200-500ms (MISS, then cached again)
- ✅ Server logs:
[Cache] Redis SET→[Cache] Redis HIT - ✅ Redis: Key
nextjs:/app-isr/pageexists with TTL
Failure Signs:
- ❌ เวลา generate เปลี่ยนทุกครั้ง → ไม่มี cache
- ❌ Server error: Connection timeout
- ❌ Redis shows no keys
Concern: Dynamic route ต้อง cache ได้ตาม slug
Steps:
- เปิด
/app-isr/1→ จดเวลา - เปิด
/app-isr/2→ ต้องเป็น data คนละอันกับ #1 - กลับไป
/app-isr/1→ เวลาต้องเหมือนเดิม (cached) - ยิง
/api/revalidate?tags=photos→ Purge cache - เปิด
/app-isr/1อีกครั้ง → เวลาต้องเปลี่ยน
Expected Results:
- ✅ แต่ละ slug cached แยกกัน
- ✅ Tag-based revalidation ทำงาน
- ✅ Redis keys:
nextjs:/app-isr/1/page,nextjs:/app-isr/2/page
Failure Signs:
- ❌ ทุก slug ได้ data เดียวกัน
- ❌ Purge ไม่ทำงาน
Concern: Pre-generated at build time, ควร cached ตลอด
Steps:
yarn build→ ดูว่า pre-render สำเร็จyarn start→ เปิด/app-ssg- Refresh หลายครั้ง → เวลา generate ต้องไม่เปลี่ยน
- รอนาน ๆ → เวลาก็ยังไม่เปลี่ยน (ไม่มี revalidate)
Expected Results:
- ✅ Build output:
✓ /app-ssg (static) - ✅ Response time: < 10ms (fully static)
- ✅ เวลา generate ไม่เปลี่ยนเลย
Failure Signs:
- ❌ Build output:
ƒ /app-ssg(dynamic symbol) - ❌ เวลาเปลี่ยนบ้าง
Concern: fetch() ภายใน API ต้องถูก cache ตาม revalidate time
Steps:
- เปิด
/api/cached-fetchครั้งแรก → ดูduration(ควร ~100-500ms) - Refresh ทันที → ดู
duration(ควร < 10ms) - เช็ค
cached: truefield - รอ 60+ วินาที → Refresh →
cached: false
Expected Results:
- ✅ First call:
duration: 150ms,cached: false - ✅ Subsequent:
duration: 3ms,cached: true - ✅ After 60s:
duration: 120ms,cached: false→ then cached again - ✅ Server logs:
[Cache] Redis SETfor fetch cache
Failure Signs:
- ❌ Duration always > 100ms (not cached)
- ❌
cachedalways false
Manual Verification:
# Call multiple times
curl http://localhost:3000/api/cached-fetch
# Check duration fieldConcern: ต้องไม่ถูก cache เลย
Steps:
- เปิด
/api/real-timeหลายครั้ง - ดู
duration→ ต้อง > 50ms ทุกครั้ง - ดู
requestId→ ต้องเปลี่ยนทุกครั้ง - ดู
cached→ ต้องfalseทุกครั้ง
Expected Results:
- ✅ Every request:
duration: 100-500ms - ✅
cached: falsealways - ✅
requestIdchanges every time - ✅ NO cache logs in server
Failure Signs:
- ❌ Duration < 50ms (accidentally cached!)
- ❌ Same
requestIdon refresh
Concern: ระวัง JSON.stringify Buffer, ควร handle Buffer → Base64
Steps:
- เปิด
/galleryครั้งแรก → รูปทั้งหมดโหลดได้ - เช็ค Network tab → ดู
/_next/image?url=...requests - Refresh → รูปโหลดเร็วขึ้น (cached)
- เช็ค server logs → ต้องไม่มี error เรื่อง Buffer
Expected Results:
- ✅ All 12 images load successfully
- ✅ No console errors
- ✅ Server logs: NO "Cannot stringify Buffer" error
- ✅ Server logs:
[Cache]entries for image optimization - ✅ Network: Image requests fast after first load
Failure Signs:
- ❌ Server crash with "TypeError: Cannot stringify Buffer"
- ❌ Images show broken icon (□)
- ❌ Redis errors in logs
- ❌ Memory spike (Buffer not compressed)
Manual Verification:
# Check Redis for image keys
redis-cli KEYS "nextjs:*image*"
# Check if data is Base64 (not raw buffer)
redis-cli GET "nextjs:<some-image-key>" | head -c 100
# Should see Base64 string, NOT binary garbageCode to Verify:
- Check
cache-handler-v4.jslines 229-263 - Verify
parseBuffersToStrings()is called - Verify
convertStringsToBuffers()is called
Concern: ISR ใช้ Cache Handler เดียวกันกับ App Router
Steps:
- เปิด
/page-static→ จดเวลา - Refresh ภายใน 60 วินาที → เวลาเหมือนเดิม
- รอ 60+ วินาที → เวลาเปลี่ยน
Expected Results:
- ✅ Same behavior as App Router ISR
- ✅ Redis keys exist
- ✅ Cache HIT/MISS pattern same as
/app-isr
Concern: SSR ไม่ควรถูก cache
Steps:
- เปิด
/page-serverหลายครั้ง - เวลา generate ต้องเปลี่ยนทุกครั้ง
- Response time > 100ms ทุกครั้ง
Expected Results:
- ✅ Always fresh data
- ✅ No cache logs for this route
- ✅ Redis has NO keys for
/page-server
Failure Signs:
- ❌ เวลาไม่เปลี่ยน (accidentally cached)
Concern: Pages Router API ทำงานเป็น serverless function ธรรมดา
Note: ไม่มีตัวอย่างใน repo นี้ แต่ถ้าสร้าง:
Expected:
- ✅ ทำงานปกติ (no cache involved)
- ✅ NO cache logs
- ✅ ไม่ต้อง config cache handler
Steps:
docker-compose up -d redisyarn dev- Check logs:
[CacheHandler] Connected to Redis. - เทสหน้าต่าง ๆ → ต้อง cache ลง Redis
Expected:
- ✅ Log: "Connected to Redis"
- ✅ Log:
[Cache] Redis SET,[Cache] Redis HIT - ✅
redis-cli KEYS "nextjs:*"→ มี keys
Steps:
docker-compose stop redis(ปิด Redis)yarn dev- Check logs:
Failed to connect to Redis+Falling back to LRU handler - เทสหน้าต่าง ๆ → ต้องทำงานได้ (ใช้ in-memory)
Expected:
- ✅ Log: "Failed to connect Redis client"
- ✅ Log:
[Cache] LRU SET,[Cache] LRU HIT - ✅ App ยังทำงานได้ปกติ
- ✅ NO errors, NO crashes
Failure Signs:
- ❌ App hangs forever
- ❌ Timeout > 5 seconds
- ❌ Crashes with connection error
Concern: ประหยัดพื้นที่ Redis
Steps:
# Check if data is compressed
redis-cli GET "nextjs:/app-isr/page" | wc -c
# Should be Base64 string (compressed)
# Raw JSON would be much largerExpected:
- ✅ Stored value is Base64 string
- ✅ Smaller than raw JSON (compression working)
Code to Check:
cache-handler-v4.jslines 190-192 (gzip)cache-handler-v4.jslines 110-112 (gunzip)
Concern: ไม่ให้ JSON.stringify Buffer โดยตรง
Verification:
- เปิด
/gallery(loads images) - Check server logs → NO errors
- Check
parseBuffersToStrings()is called (line 182) - Check
convertStringsToBuffers()is called (line 117)
Expected:
- ✅ Buffers converted to Base64 before JSON.stringify
- ✅ Base64 converted back to Buffer on retrieval
- ✅ NO "Cannot stringify" errors
Steps:
redis-cli KEYS "nextjs:*"Expected:
- ✅ Keys have
nextjs:prefix - ✅ Easy to identify (e.g.,
nextjs:/app-isr/page) - ✅ Implicit tags:
nextjs:__revalidated_tags__
Steps:
# Set ISR page with revalidate: 300
# Check TTL
redis-cli TTL "nextjs:/app-isr/page"
# Should show ~300 seconds or lessExpected:
- ✅ TTL set correctly based on
lifespan.expireAt - ✅ Key auto-expires after TTL
- ✅ New request regenerates cache
Code to Check:
cache-handler-v4.jslines 195-200 (EXAT)
Concern: On-demand revalidation ต้องทำงาน
Steps:
- เปิด
/app-isr(uses tag:photos) - จดเวลา generate
- ยิง
GET /api/revalidate?tags=photos - Refresh
/app-isr→ เวลาต้องเปลี่ยน
Expected:
- ✅ API response:
{ revalidated: true, results: [...] } - ✅ Server log:
[API] Revalidated tag: photos - ✅ Next request: Cache MISS → regenerate
- ✅ Redis:
__revalidated_tags__hash updated
Verification:
redis-cli HGET "nextjs:__revalidated_tags__" "photos"
# Should show timestampSteps:
- เปิด
/app-isr - ยิง
GET /api/revalidate?path=/app-isr - Refresh → ข้อมูลเปลี่ยน
Expected:
- ✅ Path-based purge works
- ✅ Only that path revalidated
Setup: Deploy to K8s with 3 replicas
Steps:
- Request
/app-isr→ goes to Pod A (check hostname) - Pod A caches to Redis
- Request again → might go to Pod B
- Pod B should get cache HIT from Redis
Expected:
- ✅ All pods show same generated time (shared cache)
- ✅ Logs from different pods show
Redis HIT - ✅ Consistent data across all pods
Failure Signs:
- ❌ Each pod shows different time (separate caches)
- ❌ Logs show
LRU HITinstead ofRedis HIT
Manual Test:
# Hit endpoint multiple times
for i in {1..20}; do
curl -s http://<load-balancer>/app-isr | grep "Generated at"
done
# All should show SAME timestamp (if within revalidate window)Steps:
- เปิด
/admin - กรอก path
/app-isr→ กด Purge - ตรวจสอบ response แสดงผลสำเร็จ
- เปิด
/app-isr→ ข้อมูลเปลี่ยน
Expected:
- ✅ UI ใช้งานได้ง่าย
- ✅ แสดง success message
- ✅ Cache purge ทำงานจริง
Steps:
- เปิด
/stats - ดู Cache keys, metrics
Expected:
- ✅ แสดง Redis connection status
- ✅ แสดง cache keys ที่มีอยู่
- ✅ แสดง metrics (ถ้ามี)
- Redis running:
docker-compose up -d redis - App running:
yarn dev - All App Router pages work
- All Pages Router pages work
- All API routes work
- Image gallery loads without errors
- Tag-based revalidation works
- Path-based revalidation works
-
yarn buildsucceeds - No build-time Redis errors
- Static pages pre-rendered
-
yarn startworks - All caching behaviors same as dev
- Stop Redis:
docker-compose stop redis - App starts successfully (no hang)
- LRU cache logs appear
- Pages work (slower, per-pod cache)
- No errors or crashes
- Deploy to K8s with 3 replicas
- All pods healthy
- Load balancer distributes traffic
- Cache shared across pods
- Pod hostname visible on pages
- Consistent cache behavior
| Issue | Symptom | Solution |
|---|---|---|
| Cache not working | Data always fresh | Check next.config.ts has cacheHandler |
| Redis timeout | App hangs on startup | Check Redis is running, check REDIS_URL |
| Buffer stringify error | Image pages crash | Verify parseBuffersToStrings() is called |
| Tag purge not working | Data doesn't refresh after purge | Check tag names match |
| Per-pod cache | Each pod different time | Check Redis connection (might be using LRU) |
| Build errors | Redis connection during build | Handler should skip Redis in build phase |
## Test Execution Report
**Date:** YYYY-MM-DD
**Tester:** [Name]
**Environment:** Local / K8s / EKS
**Redis:** Available / Unavailable
### Test Results
| Test Case | Status | Notes |
|-----------|--------|-------|
| `/app-isr` cache | ✅ / ❌ | |
| `/api/cached-fetch` | ✅ / ❌ | |
| `/gallery` images | ✅ / ❌ | |
| Tag revalidation | ✅ / ❌ | |
| Redis fallback | ✅ / ❌ | |
| Multi-pod cache | ✅ / ❌ | |
### Issues Found
1. [Description]
2. [Description]
### Screenshots
- [Attach screenshots of errors, logs, etc.]POC ถือว่าผ่านเมื่อ:
- ✅ ทุกหน้าใน App Router cache ได้ถูกต้อง
- ✅ API routes cache ตามที่กำหนด (cached-fetch) และไม่ cache ตามที่กำหนด (real-time)
- ✅ Image optimization ไม่ error
- ✅ Tag-based และ Path-based revalidation ทำงาน
- ✅ Redis พัง → Fallback to LRU สำเร็จ (ไม่ crash)
- ✅ Multi-pod → Cache shared ผ่าน Redis
- ✅ ไม่มี memory leak, ไม่มี Buffer errors
- ✅ Build succeeds, production mode works
ใช้เอกสารนี้ร่วมกับ automated test script (test-cache.sh) สำหรับ QA ที่สมบูรณ์ครับ!