← FRICLAWD บันทึกจากงานจริง
automation · debugging

บอทแจ้งเตือนส่งซ้ำ เกิดจากอะไร และแก้ยังไงให้หายขาด

ข้อความเดิมเด้งเข้ามาสองครั้ง ห่างกันไม่กี่วินาที หลายคนคิดว่าเป็นความบังเอิญของเครือข่าย แล้วปล่อยผ่าน แต่จริง ๆ มันมีสาเหตุที่อธิบายได้ และเกือบทั้งหมดมาจากสี่แบบนี้

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

สี่ข้อต่อไปนี้เรียงตามความถี่ที่เจอจริง พร้อมวิธีแก้ที่ใช้ได้

สาเหตุที่ 1รอบงานทับรอบตัวเอง

อาการ: ส่งซ้ำเฉพาะตอนที่มีงานเยอะ ช่วงปกติไม่เป็น และสองข้อความห่างกันประมาณเท่ากับรอบเวลาที่ตั้งไว้พอดี

ตั้งให้ทำงานทุกนาที แต่ข้างในมีงานหนัก เช่นสร้างภาพหรือเรียก API หลายชั้น พอรอบหนึ่งใช้เวลาเกินหนึ่งนาที รอบถัดไปจะเริ่มทำงานทั้งที่รอบเก่ายังไม่จบ ทั้งสองรอบมองเห็นงานชิ้นเดียวกันว่า "ยังไม่ได้ส่ง" จึงส่งกันคนละที

เคสที่ผมเจอคือการ์ดแจ้งผลที่ต้องสร้างภาพก่อนส่ง รอบหนึ่งใช้เวลาเกินนาที ผลคือเหตุการณ์เดียวได้ภาพสองใบคนละแบบ แล้วส่งออกไปทั้งคู่

วิธีแก้

จำกัดงานหนักให้ทำทีละชิ้นต่อรอบ ที่เหลือตกไปรอบถัดไป แล้วต้องมีตัวจำว่าชิ้นไหนทำไปแล้ว ไม่ใช่พึ่งเวลาอย่างเดียว ถ้ายังไม่พอ ให้ตั้งธงล็อกไว้ตอนเริ่มทำงานและปลดตอนจบ รอบที่มาทีหลังเห็นธงแล้วข้ามไปเลย

สาเหตุที่ 2ตัวกันซ้ำที่กันไม่ได้จริง

อาการ: มีโค้ดเช็คแล้วว่า "ถ้าเคยส่งแล้วให้ข้าม" แต่ยังส่งซ้ำอยู่ดี และมักเกิดตอนสองรอบทำงานพร้อมกัน

โครงสร้างที่เขียนกันทั่วไปคือ อ่านค่าว่าเคยส่งหรือยัง ถ้ายัง ให้ส่ง แล้วค่อยบันทึกว่าส่งแล้ว ปัญหาคือช่วงระหว่าง "อ่าน" กับ "บันทึก" มีช่องว่างเวลาอยู่ ถ้าอีกรอบหนึ่งอ่านในจังหวะเดียวกัน มันจะเห็นว่ายังไม่เคยส่งเหมือนกัน แล้วส่งทั้งคู่

ที่เข้าใจผิดกันมากคือคิดว่าฐานข้อมูลแบบ key-value ธรรมดาจะกันได้ แต่มันไม่รับประกันว่าการอ่านกับเขียนจะเกิดแบบต่อเนื่องกันโดยไม่มีใครแทรก ยิ่งถ้าข้อมูลกระจายหลายเครื่อง ค่าที่อ่านได้อาจเป็นค่าเก่าด้วยซ้ำ

วิธีแก้

ต้องให้การ "จอง" สิทธิ์ส่งเกิดขึ้นในที่เดียวที่ทำงานทีละคำสั่งจริง ๆ เช่นใช้หน่วยประมวลผลที่ผูกกับเหตุการณ์นั้นตัวเดียว หรือใช้ฐานข้อมูลที่รองรับการเขียนแบบมีเงื่อนไข (เขียนได้เฉพาะเมื่อยังไม่มีคีย์นี้) แล้วให้ผู้ที่จองได้เท่านั้นเป็นคนส่ง

หลักคิดคือเปลี่ยนจาก "ถามว่าเคยส่งไหม" เป็น "ขอสิทธิ์ส่ง" ซึ่งมีผู้ชนะได้คนเดียวเสมอ

สาเหตุที่ 3รหัสประจำเหตุการณ์เปลี่ยนค่าได้

อาการ: ส่งซ้ำแบบห่างกันนาน ๆ ไม่ใช่วินาที และเนื้อหาสองข้อความต่างกันนิดหน่อย

อันนี้เนียนที่สุดและหายากที่สุด ตัวกันซ้ำทำงานถูกต้องทุกอย่าง แต่รหัสที่ใช้ระบุว่า "นี่คือเหตุการณ์เดียวกัน" ดันประกอบจากข้อมูลที่เปลี่ยนได้

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

วิธีแก้

ประกอบรหัสจากสิ่งที่ไม่มีวันเปลี่ยนเท่านั้น เช่นรหัสเหตุการณ์จากต้นทาง บวกลำดับที่ ไม่เอาชื่อ สถานะ หรือข้อความมาปน ถ้าต้นทางมีรหัสของตัวเองอยู่แล้วให้ใช้ของเขาเลย และตรวจว่ารหัสเดียวกันเมื่อคำนวณซ้ำในวันถัดไปยังได้ค่าเดิม

สาเหตุที่ 4สองระบบต่างคิดว่าตัวเองมีหน้าที่ส่ง

อาการ: ส่งซ้ำทุกครั้งอย่างสม่ำเสมอ ไม่ใช่บางครั้ง และมักเริ่มเกิดหลังจากเพิ่งเพิ่มเครื่องมือใหม่เข้าระบบ

เกิดตอนที่มีสองชั้นทำงานต่อกัน เช่นมีตัวสร้างเนื้อหาอยู่แล้ว แล้วเพิ่มตัวจัดการเวิร์กโฟลว์มาเรียกใช้ ตัวจัดการเรียกให้สร้างเนื้อหา แล้วเอาผลลัพธ์ไปส่งเอง แต่ตัวสร้างเนื้อหาก็ส่งของมันเองด้วยตามค่าตั้งต้น ผลคือผู้รับได้สองครั้งทุกครั้ง

กรณีนี้เจอบ่อยมากเวลาเอาเครื่องมือใหม่มาครอบระบบเดิม เพราะเครื่องมือเดิมมักตั้งค่าเริ่มต้นให้ส่งเองเสมอ

วิธีแก้

กำหนดให้ชัดว่า ใครคือเจ้าของหน้าที่ส่ง แล้วปิดของอีกฝั่ง วิธีที่สะอาดคือให้ตัวสร้างเนื้อหามีโหมดที่ทำงานแล้วคืนผลลัพธ์กลับ โดยไม่ส่งเอง และให้ตัวจัดการเวิร์กโฟลว์เรียกโหมดนั้นเสมอ ไม่ใช่หวังว่าคนตั้งค่าจะจำได้

วิธีหาว่าเป็นแบบไหน

ดูจากลักษณะของการซ้ำก่อน จะแคบลงได้เร็วมาก

และสิ่งที่ควรมีตั้งแต่แรกคือ ตัวตรวจจับการซ้ำ — เก็บบันทึกว่าส่งอะไรไปเมื่อไหร่ แล้วมีงานที่วิ่งตรวจเป็นระยะว่า มีเหตุการณ์ไหนถูกส่งมากกว่าหนึ่งครั้งหรือเปล่า เพราะการซ้ำที่อันตรายที่สุดคือแบบที่เกิดนาน ๆ ครั้งจนไม่มีใครสังเกต

ไม่อยากไล่แก้เองทีละจุด

ชุดเวิร์กโฟลว์ n8n ของเรามีตัวรับ error กลางและตัวเฝ้าระบบที่ออกแบบ มาพร้อมกลไกกันซ้ำตั้งแต่ต้น พร้อมคู่มือไทยบอกทีละจุดว่าต้องแก้อะไรก่อนใช้

ดูชุดเวิร์กโฟลว์ →

อ่านต่อ: 9 เวิร์กโฟลว์ n8n ที่ธุรกิจไทยใช้จริง · LINE OA โควตาหมดกลางเดือน แก้ยังไง