Skip to main content

การคำนวณระดับสมาชิก Loyalty ประจำวัน

ภาพรวม

โปรแกรมสะสมแต้มที่เปิดใช้ระบบระดับสมาชิก เช่น Silver, Gold, Platinum จำเป็นต้องประเมินระดับใหม่เป็นระยะ

เหตุผลที่งานนี้ต้องเป็น cron แทนที่จะทำงานตาม event คือหน้าต่างการวัดเป็นแบบ rolling ลูกค้าอาจถูกลดระดับโดยที่ไม่ได้ทำอะไรเลย เพียงเพราะยอดซื้อเก่าหลุดออกจากช่วง 3 เดือนล่าสุด ไม่มี event ใดจากฝั่งลูกค้าที่จะกระตุ้นการคำนวณนั้นได้ จึงต้องมีตัวที่เดินตรวจตามเวลา

งานนี้ถูกออกแบบให้เป็น เส้นทางเดียวที่สามารถลดระดับสมาชิกได้ ส่วนการเลื่อนระดับขึ้นจะเกิดขึ้นทันที ณ จุดชำระเงินผ่านฟังก์ชันสะสมแต้มฝั่ง client-api เพราะไม่ควรมีลูกค้ารายใดถูกลดระดับกลางการทำรายการ ต่อหน้าพนักงานและคิวลูกค้าคนอื่น

Business Flow

งานทำงานเวลา 03:00 น. ของทุกวัน ตามตาราง 0 3 * * * บน profile cron-scheduler เวลาดังกล่าวถูกเลือกเพราะอยู่หลังเที่ยงคืน ทำให้ช่วง "3 เดือนล่าสุด" หมายถึงวันเต็ม และเป็นช่วงที่ระบบเงียบ ซึ่งสำคัญเพราะงานนี้แตะทุกบัญชีบนแพลตฟอร์ม

  1. ดึงทุกโปรแกรมใน loyalty.program ที่เปิดใช้ระบบ tier และยังไม่ถูกแทนที่ พร้อมค่ากำหนด mode, tier_window_months, tier_fallback และ tier_fallback_tier_id
  2. ประมวลผลทีละโปรแกรม โปรแกรมที่เกิดข้อผิดพลาดจะถูกบันทึก log แล้วข้ามไปตัวถัดไป เพราะการกวาดข้อมูลทั้งแพลตฟอร์มรายคืนต้องไม่หยุดเพียงเพราะร้านเดียวมีปัญหา
  3. โหลดบันไดระดับสมาชิก ซึ่งประกอบด้วยลำดับขั้น เงื่อนไข ระยะเวลาหน้าต่างของแต่ละขั้น และค่าระดับเริ่มต้น
    • หากโปรแกรมเปิดใช้ระบบ tier แต่ยังไม่ได้นิยามระดับใดเลย ระบบจะไม่ทำอะไรทั้งสิ้น เพราะการลดระดับทุกคนเนื่องจากการตั้งค่ายังไม่เสร็จถือเป็นความเสียหายที่ไม่จำเป็น
  4. ดึงทุกบัญชีใน loyalty.account ของ OA นั้นพร้อมระดับปัจจุบัน โดยใช้ LEFT JOIN เพื่อให้บัญชีที่ไม่มียอดในหน้าต่างเลยยังปรากฏด้วยค่า 0 แทนที่จะหายไป เพราะกลุ่มนี้คือกลุ่มที่ควรถูกลดระดับพอดี
  5. คำนวณสถิติแยกตามหน้าต่างของแต่ละระดับ เนื่องจากแต่ละระดับสามารถกำหนดหน้าต่างของตัวเองได้ โดยยิง query หนึ่งครั้งต่อหนึ่งหน้าต่างที่แตกต่างกัน สถิติที่วัดได้แก่ ยอดใช้จ่าย จำนวนคำสั่งซื้อ คะแนนสะสม และจำนวนเดือนที่เป็นสมาชิก
  6. ประเมินเงื่อนไขของแต่ละระดับ โดยเงื่อนไขประกอบด้วยตัวเชื่อมแบบ and หรือ or และรายการกฎย่อยที่ระบุ metric, operator และค่าที่ใช้เทียบ จากนั้นเลือกระดับสูงสุดที่ผ่านเงื่อนไข
  7. เทียบผลที่ได้กับระดับปัจจุบันและนโยบาย tier_fallback เพื่อตัดสินว่าจะคงระดับเดิม เลื่อนขึ้น หรือลดลงไปที่ระดับใด
  8. เขียนระดับใหม่ลง loyalty.account พร้อมบันทึกประวัติการเปลี่ยนระดับ

ไฟล์และฟังก์ชันหลัก

ไฟล์หน้าที่
internal/cronscheduler/loyalty_tier.goLoyaltyTierService.Run เป็น entry point ของ cron โดยมีฟังก์ชันย่อย runProgram, loadLadder, statsForWindow, applyChange, qualifiesForTier, matchTierRule, tierStatFor, pickTierByRules, resolveFromEarned, parseTierConditions และโครงสร้าง tierRow, tierStats, tierRule, tierConditions
internal/cronscheduler/loyalty_tier_test.goUnit test ของ logic การเลือกระดับสมาชิก
cmd/worker/main.gorunCronScheduler — จุดที่ลงทะเบียน job ด้วยตาราง 0 3 * * *

งานนี้ไม่มีคิวที่เกี่ยวข้อง เป็น cron ล้วน

จุดเชื่อมต่อกับ Service อื่น

  • ตารางใน schema loyaltyprogram (ค่า tier_enabled, tier_window_months, tier_fallback), tier (บันไดระดับพร้อมเงื่อนไขแบบ jsonb และ window_months), account (ฟิลด์ tier_id) และตารางธุรกรรมที่ใช้คำนวณยอดใช้จ่าย คำสั่งซื้อ และคะแนน
  • PostgreSQL อย่างเดียว — ไม่ใช้ Redis, RabbitMQ หรือ LINE API
  • client-api-go — เป็นผู้เลื่อนระดับขึ้นทันทีตอนสะสมแต้ม ซึ่งเป็นคนละทิศทางกับงานนี้
  • cms-api-go — เจ้าของหน้าตั้งค่าบันไดระดับและเงื่อนไขของแต่ละระดับ