การนำเข้ารายชื่อผู้ใช้จากไฟล์ CSV
ภาพรวม
ลูกค้าที่มีรายชื่อ LINE User ID อยู่แล้ว เช่นกรณีย้ายข้อมูลมาจากระบบเดิม สามารถอัปโหลดไฟล์ CSV เข้ามาเพื่อสร้างแถว line_user ในระบบได้
งานนี้เป็น long-running job ที่ตรวจความถูกต้องทีละรายการ ดึงโปรไฟล์จาก LINE บันทึกผลลัพธ์รายแถว สรุปสถิติ และเก็บถาวรรายละเอียดขึ้น S3 เมื่อทำงานเสร็จ
เนื่องจากเป็นงานที่ใช้เวลานานและมีโอกาสล้มเหลวกลางทาง ระบบจึงมีกลไกรองรับสามชั้น คือ retry ได้สูงสุด 2 ครั้ง มี Redis lock กันงานซ้อน และมีคำสั่ง re-process สำหรับ import ที่ค้างอยู่
Business Flow
- รับ payload ชนิด
LineUserImportCSVUserPayloadซึ่งประกอบด้วยimportId,lineOaIdและorganizationId - ตั้ง Redis flag ที่ key
LINE_USER:<REDIS_KEY_IMPORT_CSV_USER_PROCESSING>:<importId>เพื่อกันไม่ให้งานเดียวกันถูกประมวลผลซ้อนกัน - โหลดแถว
importจากฐานข้อมูล แล้วอ่านไฟล์ CSV จาก S3 ด้วยGetFileContent validateDelimiterตรวจว่าไฟล์ใช้ตัวคั่นถูกต้อง จากนั้นparseLineUserIDsแยกรายชื่อออกมา- ประมวลผลทีละรายการผ่าน
processOneImportUser- ตรวจรูปแบบด้วย regular expression
^U[a-f0-9]{32}$หากไม่ผ่านจะบันทึกเป็น invalid พร้อมเหตุผล - ตรวจว่ามีแถว
line_userอยู่แล้วหรือไม่ผ่านcheckLineUserExistsหากมีจะนับเป็น duplicate - หากเป็นผู้ใช้ใหม่ จะดึงโปรไฟล์จาก LINE ด้วย
getLineUserProfileแล้วบันทึกลงตารางimport_detail
- ตรวจรูปแบบด้วย regular expression
- ประมวลผลเป็น batch ละ 100 รายการ พร้อมอัปเดตความคืบหน้ากลับลงแถว
importผ่านupdateImport saveLineUserAccountสร้างแถวline_userจริงจากข้อมูลในimport_detailที่ผ่านการตรวจแล้วupdateImportSummaryสรุปตัวเลขรวม ได้แก่ total, success, failed และ duplicateemitAttributeChangeBatchpublish รายชื่อผู้ใช้ใหม่เข้าคิวattribute_changeเพื่อให้ trigger engine ประเมินกฎกับผู้ใช้ที่เพิ่งเข้าระบบarchiveImportDetailดึงข้อมูลimport_detailทั้งหมดออกมาเป็นไฟล์แล้วอัปโหลดขึ้น S3 ที่private/<lineOaHash>/line-user-archive/เพื่อควบคุมขนาดตารางในระยะยาว- หากงานล้มเหลว ระบบจะ retry สูงสุด 2 ครั้งตามค่าคงที่
maxRetriesจากนั้นจึงทำเครื่องหมายว่า import ล้มเหลว ส่วนฟังก์ชันReProcessImportCSVUserมีไว้กวาด import ที่ค้างอยู่ในสถานะ pending
ไฟล์และฟังก์ชันหลัก
internal/lineuser/import_service.go— ไฟล์หลักของงานนี้ ขนาดประมาณ 1,000 บรรทัดImportService.ProcessImportCSVUser(ctx, payload)— entry pointprocessOneImportUser(),getLineUserProfile(),parseLineUserIDs(),validateDelimiter()checkLineUserExists(),createImportDetails(),saveLineUserAccount()updateImport(),updateImportSummary(),emitAttributeChangeBatch()archiveImportDetail(),getImportDetails(),ReProcessImportCSVUser()- ค่าคงที่ที่สำคัญ:
maxRetriesเท่ากับ 2,batchSizeเท่ากับ 100 และfolderLineUserArchive
internal/lineuser/consumer.go—Consumer.HandleImportCSVUsercmd/worker/integration.go—lineUserStorageซึ่งเป็น adapter ของ s3x- คิวที่เกี่ยวข้อง: consume จาก
line_import_csv_userและ publish ไปยังattribute_change(runtime profilemain)
จุดเชื่อมต่อกับ Service อื่น
- ต้นทางของงาน — cms-api-go โดเมน import เมื่อผู้ใช้อัปโหลดไฟล์แล้วกดเริ่มนำเข้า
- ฐานข้อมูล —
import(สถานะและสถิติ),import_detail(ผลลัพธ์รายแถว),line_user(สร้างแถวจริง) และline_oa - S3 — อ่านไฟล์ CSV ต้นทาง และเขียนไฟล์เก็บถาวรที่
private/<lineOaHash>/line-user-archive/ - Redis — key
LINE_USER:IMPORT_CSV_USER_PROCESSING:<importId>โดยส่วน prefix ปรับได้ผ่านตัวแปรREDIS_KEY_IMPORT_CSV_USER_PROCESSING - LINE API —
GET /v2/bot/profile/{userId} - RabbitMQ — publish ต่อไปยังคิว
attribute_changeซึ่ง trigger engine เป็นผู้บริโภค - ความต่างจากงาน import mapping — งานนี้เป็นการ สร้างผู้ใช้ใหม่ ส่วนงาน import mapping เป็นการ เติมข้อมูลให้ผู้ใช้ที่มีอยู่แล้ว