Skip to content

2.5 · Data flow + caching

บทนี้เล่าว่าข้อมูลเคลื่อนที่ในระบบอย่างไร — เข้าทางไหน ออกทางไหน และ Redis "cache" ที่หลายคนคิดว่ามี แท้จริงแล้วใช้งานเกือบไม่ได้เลย


Data flow แบบแบ่งตามทิศทาง

       (write)                          (read)
          │                                │
          ▼                                ▼
  ┌───────────────────┐         ┌────────────────────┐
  │ end-user แก้ข้อมูล  │         │ end-user อ่านข้อมูล │
  └─────────┬─────────┘         └─────────┬──────────┘
            │                             │
            │ mutation                    │ query
            ▼                             ▼
       vtrc-api (MariaDB)            vtrc-api (proxy)
            │                             │
            │ sync (batch)                │ GraphQL via END_POINT_CENTRALIZE
            ▼                             ▼
         HRMI/MSSQL                  cu-central-api


                                     MSSQL (HRMI)

หลักสำคัญ — write ไป MariaDB ก่อน → แล้ว sync ไป HRMI ใน batch แต่ read ดึง live จาก HRMI ทุกครั้ง (ผ่าน cu-central-api)


กฎเหล็กเรื่อง data ownership

ข้อมูลSource of truthหมายเหตุ
ข้อมูลส่วนตัวพนักงาน (ชื่อ, นามสกุล, identityCard)HRMIVTRC อ่านอย่างเดียว
ที่อยู่, เบอร์โทรHRMIแก้ไม่ได้ใน VTRC
บัญชีธนาคารHRMI
Passwordcu-central-api + HRMIforgetPassword → override HRMI
ข้อมูลการลา, สวัสดิการ, กองทุนMariaDB (VTRC)VTRC เป็น source
Tax draft (ความคุมลดหย่อน)MariaDB → sync HRMIsync ใน batch
Profile beneficiary (กองทุน)MariaDB
คำขอทั้งหมดMariaDB
Session, User, RoleMariaDB

Read flow — "live query ทุกครั้ง"

VTRC อ่าน HR data แบบ ไม่มี cache จริง แม้จะมี Redis อยู่ใน topology

พนักงานเปิดสลิป


vtrc-api resolver → controller → centralize bridge


cu-central-api (END_POINT_CENTRALIZE) → MSSQL


return rows กลับมาทั้งหมด

ตอนอ่านโค้ดจะเจอ setCache=true ในหลาย resolver — แต่ call site จริงใน lib/controllers/file/file.js:314-315 ถูก comment ไว้หมดแล้ว


Redis — "wired แต่ vestigial"

เปิดดู vtrc-api/api/src/lib/redis.js:1-20 — Redis module มีครบ

  • redisSet(key, value, expSeconds)
  • redisGet(key)
  • redisDelete(key)

และมี helper ระดับสูง lib/controllers/redis.controller.js:1-20

  • setCacheData(name, uid, value) → key pattern cache:{name}:{uid}, TTL 36000s (10 ชม.)
  • getCacheData(name, uid)

แต่ในโค้ดจริง แทบทุก call site ถูก comment ไว้

ไฟล์บรรทัดสถานะ
routes.js:10importimport มาแต่ไม่ใช้
routes.js:411-444ใน /file/:idcomment หมด
resolvers/post.js:7, 39-41, 103-104post resolvercomment
resolvers/course.js:6, 36-37, 57-58course resolvercomment
resolvers/hrmi.js:7importcomment ทั้งบรรทัด
lib/controllers/file/file.js:6, 314-315file controllercomment ที่จุดใช้

สรุป — Redis ใน vtrc-api เสมือนไม่มี ปัจจุบันทำหน้าที่แค่ session store ให้ cu-central-api

ทำไมถึง comment ไว้

ไม่มี git blame อธิบาย แต่เดาได้ 2 เหตุผล

  1. stale data — cache hit แล้วได้ข้อมูลเก่า ทำให้พนักงานเห็นสลิปเดือนเก่า จึงปิดไป
  2. invalidation ยาก — เพราะ data source จริงอยู่ใน HRMI ที่ VTRC ไม่ได้ควบคุม จึงไม่รู้จังหวะที่ควร invalidate

Redis ที่ยังใช้จริง

Redis ไม่ได้ตายทั้งหมด — ยังใช้ใน 2 จุด

การใช้ที่ไหนkey pattern
Session store ของ cu-central-apicu-central-api/main-api/src/lib/cache/(ตัวอย่าง pattern session:{sid})
OTP store ของ cu-central-apicu-central-api/main-api/src/lib/otp/OTP rows ใน DB + Redis

ใน vtrc-api เอง — Redis แทบไม่ได้ใช้เลย แม้ container ยังเปิดอยู่ (vtrc-api/docker-compose.yml:3-13)


Write flow — "MariaDB ก่อน → sync HRMI ทีหลัง"

เมื่อพนักงานยื่นคำขอ (ลา, เบิกสวัสดิการ, แก้ tax) ข้อมูลไปที่

1. vtrc-api บันทึกใน MariaDB (ทันที)
2. sync ไป HRMI (ใน batch — ไม่ใช่ทันที)
3. HRMI ใช้ draft คำนวณภาษีเดือนถัดไป

ตัวอย่าง — tax draft (vtrc-api/api/src/lib/controllers/tax/)

พนักงานเปิดหน้า "ความคุมลดหย่อน"


fetchTaxDraft(month, year) → ดึง draft ปัจจุบันจาก MariaDB

    │  (ถ้ายังไม่เคยกรอก → prefill จาก HRMI)

templateFormTax → ขอ form schema


พนักงานแก้ข้อมูล → createTaxDraft / updateTaxDraft


draft ถูกเก็บใน MariaDB (table TaxDraft)

    │  (sync ไป HRMI ใน batch — ไม่ใช่ทันที)

HRMI ใช้ draft คำนวณภาษีเดือนถัดไป

ระวัง — sync ไป HRMI ไม่ใช่ทันที ถ้า HR หรือพนักงานแก้ draft แล้ว HRMI ยังไม่ sync → ฝั่ง HRMI จะใช้ข้อมูลเก่า จึงต้องรอ batch window


ความสัมพันธ์ระหว่าง 2 schema ใน MariaDB

vtrc-api/api/src/connector.js:8-48 — เปิด connection 2 ตัว

ConnectionSchemaใช้ทำอะไร
dbvtrccore business data (users, sessions, leave, withdraw, fund)
db2vtrc-centralizecross-schema join tables + Session.tokenCD (จาก centralize bridge)

ตัวอย่าง — Session.tokenCD เก็บ token ที่ centralize bridge refresh แล้ว (vtrc-api/api/src/centralize/controllers/auth.js:116-124) — ใช้สำหรับ session continuity ระหว่าง vtrc-api และ cu-central-api


DB pool กับ replica

VTRC-API มี 4 replica ที่เปิด pool max: 100 ต่อ replica — รวมสูงสุด 400 connection จาก api tier เข้า MariaDB

ถ้า MariaDB max_connections ตั้งไว้ต่ำกว่านี้ → connection exhaustion ได้

cu-central-api เปิด pool 6 ตัว × max 100 → 550 connection เข้า MSSQL — เสี่ยงเดียวกัน


Cache strategy ที่ควรจะเป็น vs ที่เป็น

Featureที่ควรที่เป็น
สลิปเงินเดือนcache 1-7 วัน (TTL ตามรอบเงินเดือน)ไม่ cache — ดึง live ทุกครั้ง
โครงสร้างองค์กรcache 1 วัน (เปลี่ยนนาน)ไม่ cache
รายชื่อผู้อนุมัติcache 1 ชม.ไม่ cache
Tax draftไม่ cache (user แก้บ่อย)ไม่ cache ✓
Profile พนักงานcache 1 ชม.ไม่ cache

ถ้าทำ performance optimization — caching เป็นจุดที่ให้ผลคุ้มที่สุด เพราะ Redis พร้อมใช้ แค่เปิด comment กลับมา (แต่ต้องแก้ปัญหา invalidation ก่อน)


เคล็ดลับตอนทำงานจริง

ถ้าเจอ "ข้อมูลไม่อัปเดต"

อย่าเริ่ม clear cache Redis — เพราะแทบไม่ได้ใช้ ให้เช็คก่อนว่า

  1. ข้อมูลที่แก้ → เข้า MariaDB หรือยัง (ดู updatedAt ในตาราง)
  2. ถ้าต้อง sync ไป HRMI → sync ใน batch window หรือยัง
  3. ถ้าเป็น HR data → ต้องแก้ที่ HRMI ต้นทาง ไม่ใช่ VTRC

ถ้า HR บอกว่า "ฝั่ง HRMI ยังไม่เห็น"

เพราะ sync เป็น batch — บางครั้งต้องรอ 1-2 ชม. ขึ้นอยู่กับ cron window ถ้าเร่งด่วน HR ต้อง manual sync

"ทำไม query ช้า"

ส่วนใหญ่ไม่ใช่ที่ cache แต่ที่

  1. Session table ใหญ่ → LIKE %jti% ไม่ใช้ index
  2. HRMI query complex → MSSQL slow
  3. N+1 query ใน resolver

ลอง EXPLAIN ใน MariaDB ก่อน แล้วค่อยไปที่ centralize bridge


ขั้นตอนถัดไป

ไป บท 2.6 Concurrency + batch jobs