Telegram getUpdates offset: ป้องกันการประมวลผลซ้ำและอัปเดตสูญหาย
Telegram จะถือว่าอัปเดตได้รับการยืนยันเมื่อคุณเรียก getUpdates ด้วย offset ที่มากกว่า update_id ของอัปเดตนั้น การได้รับ response เพียงอย่างเดียวยังไม่ใช่การยืนยัน เพื่อป้องกันงานสูญหาย ให้บันทึกอัปเดตลงที่เก็บข้อมูลถาวรก่อนส่งคำขอถัดไปด้วย offset ที่สูงขึ้น และบันทึก offset ถัดไปพร้อมข้อมูลนั้น เพื่อรองรับการรีสตาร์ต โดยแยกการตรวจข้อมูลซ้ำออกจากการทำงานทางธุรกิจ
ประเด็นสำคัญ
offsetคือขอบเขตการยืนยัน ไม่ใช่เลขหน้าหรือจำนวนข้อความ- เลื่อนไปข้างหน้าเมื่ออัปเดตที่จะถูกยืนยันถูกจัดเก็บอย่างปลอดภัยครบแล้วเท่านั้น
- ให้แต่ละบอตมีผู้รับผิดชอบ polling ที่ทำงานอยู่เพียงหนึ่งตัว แล้วขยาย worker ปลายทางแทน
- กล่องรับข้อมูลถาวรช่วยปกป้องขั้นตอนรับเข้า แต่การทำงานกับระบบภายนอกยังต้องมีแผน retry ของตัวเอง
บทความนี้สมมติว่าคุณเลือกใช้ polling แล้ว หากยังตั้งค่า webhook อยู่ ให้ดู ขั้นตอนสลับ getUpdates กับ setWebhook ก่อน ประเด็นที่นี่คือการ commit ข้อมูลระหว่างคำขอ polling ที่สำเร็จ ไม่ใช่การเลือกรูปแบบรับข้อมูลใหม่
getUpdates offset ยืนยันอะไรบ้าง
เอกสาร Telegram Bot API อย่างเป็นทางการ ระบุว่า offset คือรหัสของอัปเดตแรกที่ต้องการให้ส่งกลับ หากไม่ระบุ จะเริ่มจากอัปเดตที่เก่าที่สุดซึ่งยังไม่ถูกยืนยัน เมื่อเรียกครั้งถัดไปด้วย offset ที่สูงกว่ารหัสของอัปเดตนั้น อัปเดตก็จะถูกยืนยัน
ตัวอย่างสมมติ: response มีอัปเดต 8100, 8101 และ 8102 หากเรียกครั้งถัดไปด้วย offset=8103 จะยืนยันทั้งสามรายการ แม้แอปของคุณเพิ่งประมวลผลรายการสุดท้ายเพียงรายการเดียว Telegram ไม่ได้ตรวจฐานข้อมูลหรือรอให้ CRM ทำงานเสร็จ
| วิธีลัด | ความเสี่ยง | การออกแบบที่ปลอดภัยกว่า |
|---|---|---|
| บันทึก ID สูงสุดก่อนเก็บทั้งชุด | หลังรีสตาร์ตอาจข้ามอัปเดตที่ยังไม่เคยบันทึก | commit กล่องรับข้อมูลและ offset ถัดไปพร้อมกัน |
| เลื่อน offset เมื่องานขนานที่เร็วที่สุดเสร็จ | อัปเดตก่อนหน้าที่ยังไม่เสร็จอาจถูกยืนยันด้วย | ใช้ความคืบหน้าการจัดเก็บ ไม่ใช่ลำดับที่ worker เสร็จ |
| เก็บ offset ในหน่วยความจำเท่านั้น | checkpoint หายเมื่อรีสตาร์ต | โหลด checkpoint ถาวรแยกตามบอต |
| ใช้ offset ติดลบเพื่อแก้ข้อมูลซ้ำ | อัปเดตก่อนหน้าในคิวถูกทิ้ง | ตรวจเจ้าของ polling และการตรวจซ้ำ |
Telegram ระบุชัดว่า offset ติดลบจะอ่านจากท้ายคิวและลืมอัปเดตก่อนหน้านั้น จึงไม่ใช่วิธีกู้คืนงาน production ที่ยังต้องใช้
แยกความคืบหน้าการรับเข้าจากสถานะงานธุรกิจ
แนวทางหนึ่งคือเก็บข้อมูลที่แอปเป็นเจ้าของสองส่วน: กล่องรับเข้าที่มีอัปเดตฉบับเต็ม และ checkpoint ที่เก็บ offset ถัดไป ทั้งสองส่วนเป็นแนวคิดของฐานข้อมูลภายใน ไม่ใช่ฟิลด์ใหม่ของ Telegram API
ใช้ตัวตนที่คงที่ของบอตร่วมกับ update_id เป็น unique key ของกล่องรับเข้า อย่าใช้ bot token เองเป็นคีย์ฐานข้อมูลหรือเขียนลง log เก็บอัปเดตทุกประเภทที่ได้รับ รวมถึงประเภทที่ worker ปัจจุบันยังไม่รู้จัก แล้วค่อยจำแนกภายหลัง
ลำดับ transaction ที่แนะนำ:
อ่าน offset ถัดไปที่บันทึกไว้สำหรับบอตนี้
เรียก getUpdates ด้วย offset ดังกล่าว
ถ้าชุดข้อมูลว่าง ให้คง checkpoint เดิม
หากไม่ว่าง ให้เริ่ม transaction ของฐานข้อมูล:
เพิ่มอัปเดตทุกรายการ โดยไม่เพิ่มซ้ำเมื่อ unique key มีอยู่แล้ว
บันทึก max(update_id ในชุดนี้) + 1 เป็น offset ถัดไป
commit
เรียก polling ครั้งต่อไปหลัง commit สำเร็จเท่านั้น
ให้ worker แยกต่างหากประมวลผลอัปเดตที่บันทึกไว้
นี่คือ pseudocode สำหรับการออกแบบ ไม่ใช่ polling client ที่สมบูรณ์ โดยสมมติว่ามี poller ที่ทำงานอยู่หนึ่งตัว มีที่เก็บข้อมูลถาวรที่รองรับ transaction และมี unique constraint หาก transaction ล้มเหลว ให้หยุดเลื่อน checkpoint และ retry จากค่าที่บันทึกไว้ อย่าจับข้อผิดพลาดการจัดเก็บแล้วทำต่อด้วย offset ที่สูงกว่า
หากกล่องรับเข้าและ checkpoint อยู่คนละระบบ transaction นี้จะไม่เป็น atomic โดยอัตโนมัติ ต้องออกแบบการส่งต่องานแบบถาวรและการตรวจสอบความสอดคล้อง อย่าถือว่าการเขียนสำเร็จสองครั้งเท่ากับการ commit ครั้งเดียว
ทดสอบตามจุดที่ระบบอาจหยุด
ตารางนี้เป็นกรณีทดสอบที่แนะนำ ไม่ใช่ผลการทดสอบจริง:
| จุดที่หยุด | พฤติกรรมกู้คืนที่คาดหวัง |
|---|---|
| หลังรับชุดข้อมูล แต่ก่อน commit | โหลด checkpoint เดิม และยอมรับการได้รับข้อมูลซ้ำ |
| ระหว่าง transaction | rollback แล้วต้องไม่มี checkpoint ที่อัปเดตเพียงบางส่วนค้างอยู่ |
| หลัง commit แต่ก่อน polling ครั้งถัดไป | โหลด checkpoint ใหม่ และงานที่บันทึกไว้ยังประมวลผลต่อได้ |
| หลังทำงานภายนอกสำเร็จ แต่ก่อนบันทึกว่าเสร็จ | ตรวจสอบสถานะหรือใช้ idempotency ปลายทาง คีย์รับเข้าเพียงอย่างเดียวป้องกันการทำงานซ้ำไม่ได้ |
อัปเดตซ้ำควรอ้างถึงรายการเดิมในกล่องรับเข้า แต่การมีรายการนั้นไม่ได้หมายความว่างานธุรกิจเสร็จแล้ว worker ต้องค้นหาและ retry งานที่บันทึกไว้แต่ยังไม่เสร็จได้ ในทางกลับกัน การรับข้อมูลซ้ำไม่ควรเริ่มส่งคำตอบหรือแก้ไข CRM อีกรอบโดยอัตโนมัติ
ระหว่าง deploy ให้ส่งต่อสิทธิ์ polling อย่างชัดเจน process สำหรับพัฒนาที่ลืมปิด หรือคำขอตรวจสอบด้วย offset ที่สูงขึ้น อาจยืนยันอัปเดตนอกเส้นทางจัดเก็บของคุณ อย่าให้การตรวจสอบที่คิดว่าเป็น “อ่านอย่างเดียว” เปลี่ยนความคืบหน้าของ production
ข้อจำกัดและขอบเขตของ UnifyPort
Telegram ระบุว่าเก็บอัปเดตขาเข้าไว้ไม่เกิน 24 ชั่วโมง checkpoint จึงไม่ใช่คลังข้อมูลถาวรไม่จำกัดเวลา และการลด offset ไม่สามารถกู้อัปเดตที่ยืนยันแล้วหรือหมดอายุแล้วได้ ควรตรวจช่วงที่ระบบหยุดว่าอาจมีข้อมูลสูญหายหรือไม่
หากต้องรับจากบัญชีเดิม หรือรวมงาน LINE กับ Telegram ให้เริ่มจาก เปรียบเทียบ Telegram Bot API webhook กับ webhook ขาเข้าแบบรวม อินเทอร์เฟซที่ไม่เป็นทางการของ UnifyPort ใช้อีเวนต์มาตรฐาน เช่น message.received ไม่ใช่ polling offset ของบอต
เอกสารการส่ง webhook ของ UnifyPort กำหนดข้อตกลงการยืนยันแยกต่างหาก ตั้งค่า signing_secret และตรวจ X-Device-Signature ด้วย HMAC-SHA256 บน timestamp ตามด้วยจุดและไบต์ดิบของ request จากนั้นบันทึกอีเวนต์ถาวรก่อนตอบกลับว่าสำเร็จ การ retry อีเวนต์ทั่วไปใช้ X-Device-Event-Id เดิม UnifyPort ไม่มี REST API สำหรับอ่านประวัติข้อความ และไม่รับประกันการส่ง payload ที่พลาดไปซ้ำ จึงไม่ใช่บริการกู้อัปเดต Bot API ที่ยืนยันแล้ว
คำถามที่พบบ่อย
ทำไม getUpdates ส่งอัปเดตเดิมกลับมาตลอด?
ตรวจว่าคำขอถัดไปใช้ offset ที่มากกว่า update_id เหล่านั้นจริงหรือไม่ และหลังรีสตาร์ตได้โหลด checkpoint ที่บันทึกไว้หรือไม่ ควรตรวจซ้ำอย่างปลอดภัยแทนการทิ้งคิว
ต้องรอ AI หรือ CRM เสร็จก่อนเลื่อน offset หรือไม่?
ไม่จำเป็น หากบันทึกอัปเดตฉบับเต็มแบบถาวรแล้วและ retry งานแยกได้ การเก็บในหน่วยความจำอย่างเดียวไม่ใช่การส่งต่อที่ทนต่อการหยุดทำงาน
วิธีนี้รับประกันว่าส่งคำตอบเพียงครั้งเดียวหรือไม่?
ไม่รับประกัน การจัดเก็บแบบ atomic ป้องกันงานสูญหายบางกรณี แต่การส่งอาจสำเร็จก่อน worker บันทึกว่าเสร็จ ต้องออกแบบ idempotency หรือการตรวจสอบสถานะในจุดนั้นด้วย
ขั้นตอนถัดไปและแหล่งข้อมูล
ตรวจ polling loop ตรงขอบเขตการ commit ฐานข้อมูล หากใช้ตัวรับของบัญชีรับส่งข้อความ ให้ทำตาม ข้อตกลงการส่ง webhook โดยไม่ยกตรรกะ offset ของ Bot API มาใช้
- Telegram Bot API: getUpdates และ Getting updates ตรวจสอบเมื่อ 2026-09-19
- UnifyPort: การส่ง webhook และการตรวจลายเซ็น
เปลี่ยนการเชื่อมต่อข้อความให้เป็น pipeline ผลิตภัณฑ์ที่เสถียร
เริ่มจากการส่งผ่าน API เดียว แล้วส่งข้อความขาเข้าทั้งหมดกลับสู่ระบบธุรกิจของคุณด้วย event มาตรฐาน