P Y T H O N

Celery Best Practice: ใช้ Task เบื้องหลังอย่างไรให้รอดในโปรดักชันจริง

Celery Best Practice: ใช้ Task เบื้องหลังอย่างไรให้รอดในโปรดักชันจริง

ทุกโปรเจกต์ Django ที่โตขึ้นมาถึงจุดหนึ่งจะเจอคำถามเดิม ๆ นั่นคือ "งานหนัก ๆ เช่น ส่งอีเมล ออกรายงาน หรือเรียก AI เราจะให้มันไปทำเบื้องหลังได้ไหม ไม่ให้ลูกค้ารอหน้าเว็บหมุนวน" คำตอบมาตรฐานของวงการคือ Celery ซึ่งเป็นระบบ Task Queue ที่ได้รับความนิยมสูงสุดของ Python แต่การติดตั้ง Celery ให้เปิด worker ขึ้นมาได้ไม่ยาก ปัญหาจริงคือทำยังไงให้มันทำงานอย่างเสถียรในโปรดักชันโดยไม่หลุด queue ไม่โหลดซ้ำ และไม่กลายเป็นจุดพังของระบบ บทความนี้จะพาไปดู Best Practice ที่ทีมที่เจอระบบจริงในสนามต่างใช้กันเป็นประจำ พร้อมตัวอย่างที่เห็นภาพชัดเจนว่ามันช่วยธุรกิจได้จริงอย่างไร

Celery คืออะไร ทำงานอย่างไร

Celery คือระบบที่คอยรับ "คำสั่งงาน" ที่เรียกจากเว็บแล้วนำไปรันแบบอะซิงโครนัสบนเครื่องอื่นหรือ process อื่น โดยมีองค์ประกอบหลักสามส่วน ได้แก่ Producer (โค้ดในเว็บที่สั่งงาน เช่น send_email.delay(...)), Broker (คิวกลางที่เก็บงาน เช่น Redis หรือ RabbitMQ) และ Worker (process ที่คอยดึงงานมาทำ) บวกกับ Celery Beat สำหรับงานแบบกำหนดเวลาอัตโนมัติ เช่น อัปเดตสถิติทุกเที่ยงคืน

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

Best Practices ที่โปรเจกต์จริงต้องมี

1. ออกแบบ Task ให้เป็นอะตอมและรันซ้ำได้ (Idempotent)

งานแต่ละงานควรเล็ก จบในตัวเอง และที่สำคัญคือ รันซ้ำแล้วได้ผลเหมือนเดิม เพราะในระบบจริง task อาจถูก execute ซ้ำจาก retry หรือจาก network hiccup เช่น task "หักเงินแล้วส่งอีเมลยืนยัน" ถ้ารันซ้ำอาจหักเงินสองครั้ง ทางที่ดีต้องแยกเป็น task ย่อย และเช็กสถานะก่อนทำงาน เช่น ใช้ get_or_create หรือตรวจสอบ flag ว่าชำระเงินแล้วหรือยัง กฎง่าย ๆ คือ ถ้า task ถูกเรียกซ้ำสองรอบแล้วผลไม่ผิดเพี้ยน แสดงว่าออกแบบถูกต้องแล้ว

2. ตั้ง Retry ด้วย Exponential Backoff

API ภายนอกอาจล่มหรือ timeout เป็นเรื่องปกติของโปรดักชัน ให้กำหนดให้ task retry อัตโนมัติด้วย autoretry_for เช่น retry สูงสุด 5 ครั้ง โดยระยะเวลาถี่ขึ้นเรื่อย ๆ (เช่น 30 วินาที, 1 นาที, 2 นาที) แทนที่จะยิงซ้ำถี่ ๆ จนทำให้บริการภายนอกล่มหนักกว่าเดิม และอย่าลืมว่า retry ไม่ได้แก้ทุกปัญหา ถ้าผิดพลาดจากข้อมูลผิดพลาดถาวร เช่น email ไม่ถูกต้อง ควรจบ task ทันทีและบันทึก log ไว้ ดีกว่าฝืน retry จนคิวตัน

3. ตั้ง Time Limit เพื่อกัน Worker ตายคาเครื่อง

Task ที่ไม่มีขอบเขตเวลาเป็นตัวอันตรายที่สุดต่อระบบ เช่น task ตัดวิดีโอที่ดึง network call ไปค้างจน worker ใช้หน่วยความจำหมดทั้งเครื่อง การตั้ง task_time_limit และ task_soft_time_limit จะช่วยให้ Celery ฆ่า task ที่ทำงานนานเกินไปได้ โดย soft limit เปิดโอกาสให้ task เก็บงานหรือเขียน state ก่อนตายอย่างเป็นระเบียบ นี่คือสิ่งที่หลายโปรเจกต์พลาด เพราะตอนทดสอบในเครื่องไม่เห็นปัญหา พอขึ้นจริงงานหลากหลายขึ้นก็เจ็บตัว

4. แยก Queue ตามความสำคัญของงาน

ไม่ควรยัดงานทุกประเภทลงคิวเดียว เพราะงานออกรายงานหนัก ๆ จะไปเบียดงานเร่งด่วนอย่างการยืนยัน OTP ที่ต้องรวดเร็ว ในโปรเจกต์จริงควรแยกเช่น default สำหรับงานทั่วไป, email สำหรับการส่งข้อความ และ ai สำหรับงานที่ต้องเรียกโมเดล AI โดยใช้ task_routes และระบุ queue ต่อ task และที่สำคัญคือ เปิด worker แยกกันต่อคิวด้วย concurrency ที่เหมาะสม เช่น คิว AI เปิด worker แค่ 2-4 ตัว เพราะการเรียกโมเดลกินทรัพยากรสูง ส่วนคิวอีเมลเปิดได้เยอะกว่า

5. ใช้ Redis เป็น Broker ไม่ใช่ Database

มีคนจำนวนไม่น้อยใช้ Django DB เป็น broker เพราะตั้งง่าย แต่ในโปรดักชันมันจะกลายเป็นจุดหายนะ ทั้งเรื่อง performance และข้อจำกัดของ transaction เช่น message ที่ถูก poll อาจหลุดหายเมื่อมีการ rollback ถ้าเพิ่งเริ่มแนะนำให้ใช้ Redis เป็น broker และเก็บผลลัพธ์ (result backend) ที่ Redis เช่นกัน และอย่าลืมตั้ง visibility_timeout ให้มากกว่าเวลาสูงสุดที่ task ใช้จริง เพื่อไม่ให้ task ที่กำลังทำงานถูกดึงไปทำงานซ้ำอีกเครื่อง

6. Monitor อย่างจริงจังด้วย Flower

ระบบเบื้องหลังที่ไม่มีหน้าจอ monitoring คือระเบิดเวลาที่เราไม่รู้ว่าจะระเบิดเมื่อไหร่ เครื่องมืออย่าง Flower ช่วยให้เห็นว่า queue ยาวแค่ไหน task ไหน fail บ่อย worker ตัวไหนทำงานเกินกำลัง แถมยังกำหนดเกณฑ์แจ้งเตือนผ่าน Slack หรือ Line ได้ เช่น เตือนเมื่อ task failed เกิน 10 ครั้งใน 5 นาที หรือเมื่อ queue ยาวเกิน 1,000 รายการ การมีระบบแจ้งเตือนแบบนี้จะช่วยให้ทีมแก้ปัญหาได้ก่อนลูกค้าจะเจอ

7. งานตามเวลาด้วย Celery Beat ต้องมี Scheduler เดียว

งานประจำ เช่น ส่งสรุปยอดขายประจำวัน หรือตัดข้อมูลเก่า ควรใช้ Celery Beat ซึ่งต้องรันบนเครื่องเดียวเท่านั้น หาก deploy แบบหลาย node โดยไม่ระวังจะเกิด Beat หลายตัวรันงานเดียวกันซ้ำเป็นทวีคูณ แนวทางที่นิยมคือแยก Beat ไปรันที่เครื่องเดียว หรือใช้สัญญาณ lock ใน Redis (เช่น redbeat) เพื่อให้แน่ใจว่างานประจำถูกรันจากจุดเดียวจริง ๆ

8. ระวัง Connection Pool และการเปิด Worker เกินพอดี

ทุก task ที่เปิดการเชื่อมต่อฐานข้อมูลใหม่จะกินทรัพยากรอย่างมหาศาล โดยเฉพาะเมื่อ worker ถูกตั้ง autoscale สูงเกินไป ให้ปรับ concurrency ให้พอดีกับขนาดเครื่อง เช่น worker เดียว 4 process กับ RAM 4GB สำหรับงานทั่วไป และทดสอบ load จริงก่อนขึ้นโปรดักชัน เพื่อหาจุดที่ระบบยังทำงานได้เสถียรโดยไม่กินทรัพยากรเกินจำเป็น

ตัวอย่างโจทย์จริง: ทำไม AI Agent กับ Celery คือคู่ที่ลงตัว

หลายคนอาจสงสัยว่าเรื่อง AI Agent เกี่ยวอะไรกับ Celery คำตอบคือ งานที่ AI Agent ทำส่วนใหญ่คืองานที่ต้องรอนาน เช่น วิเคราะห์ข้อความลูกค้าเป็นหมื่นข้อความต่อวันเพื่อหาความรู้สึก (Sentiment), สรุปผลการสนทนาสนับสนุนลูกค้า, ออกร่างตอบอีเมล, หรือสร้างคำแนะนำสินค้าเฉพาะบุคคล งานเหล่านี้ต้องเรียก Large Language Model ซึ่งใช้เวลาหลายวินาทีถึงนาทีต่อครั้ง ถ้าทำแบบซิงโครนัสหน้าเว็บจะค้างและลูกค้าจะหายไปก่อน แต่ถ้าส่งเข้า Celery เราสามารถจัดคิวงาน AI ให้ไล่เรียงทีละชุด ตั้ง retry เมื่อ API ของโมเดล timeout และแยกคิว AI ออกจากงานทั่วไปได้อย่างง่ายดาย

จากมุมมองธุรกิจ นี่คือคำตอบของคำถามที่ว่า AI Agent ใช้ประโยชน์กับธุรกิจอย่างไร ลองจินตนาการร้านค้าออนไลน์ที่พนักงานต้องตอบคำถามลูกค้าซ้ำ ๆ วันละร้อยข้อความ ระบบ AI Agent ที่ทำงานเบื้องหลังจะช่วยอ่านและจัดหมวดหมู่ข้อความ แท็กคำถามเร่งด่วน หรืออัปเดตสถานะสินค้าอัตโนมัติให้ พนักงานใช้เวลาไปกับลูกค้าที่ซับซ้อนจริง ๆ แทน ขณะเดียวกันการวิเคราะห์ feedback ลูกค้าแบบ batch ทุกคืนก็จะส่งผลให้ทีมเห็นแนวโน้มผลิตภัณฑ์และปรับกลยุทธ์ได้เร็วขึ้น ทั้งหมดนี้เกิดขึ้นได้โดยเว็บหลักยังโหลดไวเหมือนเดิม เพราะภาระหนักถูกทิ้งไว้ที่ Celery ทั้งสิ้น

สรุป

Celery เป็นเครื่องมือที่ทรงพลังแต่ก็โหดร้ายกับผู้ที่ไม่เคารพกฎของมัน หัวใจหลักคือการออกแบบ task ให้รันซ้ำได้ ตั้ง retry และ time limit ให้สมเหตุสมผล แยก queue ตามความสำคัญ ใช้ Redis เป็น broker มอนิเตอร์ด้วย Flower และรัน Beat แบบ single instance ซึ่งเมื่อทำครบแล้ว ระบบงานเบื้องหลังของคุณจะกลายเป็นขุมกำลังที่ทำให้เว็บรวดเร็ว รองรับ AI Agent และการเติบโตของธุรกิจได้อย่างมั่นคง

ถ้าทีมของคุณกำลังวางระบบงานเบื้องหลัง หรืออยากนำ AI Agent มาต่อยอดธุรกิจแต่ไม่แน่ใจว่าจะออกแบบอย่างไรให้ปลอดภัยและขยายได้ ทีมงาน Para-Studio จาก pythonthailand.com ซึ่งเชี่ยวชาญการพัฒนาเว็บด้วย Python-Django และระบบ AI อัตโนมัติ ยินดีช่วยออกแบบสถาปัตยกรรม Celery, คิวงาน และระบบ AI ให้เหมาะกับขนาดธุรกิจของคุณ ตั้งแต่โปรเจกต์ SME ไปจนถึงระบบระดับ enterprise เริ่มคุยกันได้ที่หน้า /contact


หากชอบบทความดีๆ โปรดติดตามพวกเราด้วยนะคะ 🙏