Vercel Serverless Function กับ Edge Function รับ Webhook ต่างกันตรงไหนเรื่อง Timeout

สรุปสั้น ๆ
Vercel มี Function สองแบบสำหรับรับ webhook คือ Node.js Serverless Function ที่รองรับ Node API เต็มรูปแบบแต่มีเพดานเวลาทำงานจำกัดตามแพ็กเกจ กับ Edge Function ที่เริ่มทำงานเร็วกว่าแต่มี Node API จำกัดคล้าย Cloudflare Workers ตัว Vercel เองไม่ได้ retry การเรียก function ที่ล้มเหลวให้อัตโนมัติ ความรับผิดชอบเรื่อง retry จึงอยู่ที่ผู้ส่ง webhook ทำให้ต้องออกแบบ idempotency ผ่าน storage ภายนอกเองเสมอไม่ว่าจะเลือก function แบบไหน
ทีมที่สร้าง webhook receiver บน Vercel มักเจอทางแยกแรกตั้งแต่เริ่มต้นคือควรใช้ Node.js Serverless Function แบบดั้งเดิม หรือ Edge Function ที่ Vercel เปิดให้ใช้เพิ่มเติมในภายหลัง ทั้งสองแบบรับ HTTP request และตอบ response ได้เหมือนกันในภาพกว้าง แต่มีรายละเอียดที่ต่างกันมากพอจะทำให้ webhook ทำงานไม่ได้ตามที่คาดถ้าเลือกผิดสำหรับ workload ที่ต้องรับมือ
ปัญหาที่ทีมมักมองข้ามคือเรื่อง timeout ที่ต่างกันตามแพ็กเกจและประเภท function ที่เลือกใช้ รวมถึงความเข้าใจผิดว่า Vercel จะ retry การเรียก function ให้เองถ้าล้มเหลว ทั้งที่จริงแล้วความรับผิดชอบเรื่อง retry เป็นของผู้ส่ง webhook ฝั่งเดียว ทำให้การออกแบบ idempotency ต้องทำเองเสมอไม่ว่าจะเลือก function ประเภทไหน
บทความนี้จะไล่ความต่างระหว่าง Node.js Serverless Function กับ Edge Function บน Vercel โดยเฉพาะในบริบทของการรับ webhook พร้อมชี้จุดที่ทำให้ webhook ล้มเหลวเงียบ ๆ ถ้าไม่เข้าใจกลไกเรื่อง timeout และ retry ให้ถูกต้อง
Vercel มี Function สองแบบสำหรับรับ Webhook: Node.js Serverless กับ Edge Runtime
Node.js Serverless Function เป็นรูปแบบดั้งเดิมที่ Vercel รองรับมาตั้งแต่ต้น รันบน Node runtime เต็มรูปแบบ เข้าถึง Node API ได้ครบ เช่น filesystem ชั่วคราวหรือ library ที่พึ่งพา native binding เฉพาะแพลตฟอร์ม เหมาะกับ webhook ที่ logic ซับซ้อนหรือต้องใช้ library ที่ยังไม่รองรับ edge runtime
Edge Function เป็นตัวเลือกที่เพิ่มมาทีหลัง รันบน runtime ที่ใกล้เคียง Web API มาตรฐานคล้ายกับ Cloudflare Workers เริ่มทำงานเร็วกว่าเพราะ isolate เบากว่า container ของ Node function แต่ก็มีข้อจำกัดคล้ายกันคือ Node API เฉพาะทางบางตัวใช้ไม่ได้ตรง ๆ ต้องตรวจสอบ compatibility ของ dependency ก่อนเลือกใช้
การเลือกระหว่างสองแบบนี้สำหรับ webhook receiver ควรพิจารณาจาก logic ที่ต้องทำหลังตรวจ signature เป็นหลัก ถ้าต้องเรียก library เฉพาะทางของ Node หรือทำงานที่ใช้เวลานานและซับซ้อน Node.js Serverless Function อาจเหมาะกว่า ถ้า logic เบาและเน้นตอบเร็วเป็นหลัก Edge Function อาจได้เปรียบเรื่อง cold start ที่สั้นกว่า
Timeout ต่างกันตามแพ็กเกจ Vercel ส่งผลต่อ Webhook ยังไง
เพดานเวลาทำงานสูงสุดต่อ request ของ Vercel Function ไม่เท่ากันในทุกแพ็กเกจ แพ็กเกจฟรีมีเพดานสั้นกว่าแพ็กเกจที่เสียเงิน และ Edge Function มักมีเพดานเวลาที่ต่างจาก Node.js Serverless Function ในแพ็กเกจเดียวกันด้วย ทีมที่ออกแบบ webhook receiver ที่มี logic ทำงานนาน เช่นเรียก API ภายนอกหลายตัวต่อกันก่อนตอบ response ควรตรวจเพดานเวลาจริงของแพ็กเกจที่ใช้อยู่ ไม่ใช่สมมติว่าจะได้เวลาเท่ากันทุกที่
ปัญหาที่เกิดขึ้นจริงคือ webhook ที่ logic ทำงานใกล้เพดานเวลาพอดี อาจทำงานสำเร็จเกือบทุกครั้งตอนทดสอบ แต่พอเข้า production ที่มี load สูงกว่าเดิมเล็กน้อย เวลาที่ใช้จริงอาจเกินเพดานได้บ้างเป็นครั้งคราว ทำให้บาง request ล้มเหลวแบบสุ่ม ๆ ที่ debug ยาก เพราะดูจาก log แล้ว logic ก็ถูกต้องทุกอย่าง เพียงแต่ใช้เวลานานเกินเพดานพอดีในบาง request
แนวทางที่ปลอดภัยกว่าคือออกแบบ webhook receiver ให้ทำเฉพาะงานที่จำเป็นก่อนตอบ response เช่นตรวจ signature และบันทึกว่าได้รับ event แล้วเท่านั้น ส่วนงานที่ใช้เวลานานควรแยกไปทำ asynchronous แทน เพื่อไม่ให้เวลาทำงานรวมต่อ request เข้าใกล้เพดานเวลาของแพ็กเกจที่ใช้อยู่ ไม่ว่าจะเลือก function ประเภทไหนก็ตาม
Retry เกิดจากฝั่งไหน Vercel เองไม่ Retry แต่ผู้ส่ง Webhook อาจ Retry
ความเข้าใจผิดที่พบบ่อยคือคิดว่า Vercel จะ retry การเรียก function ให้อัตโนมัติถ้า function นั้นล้มเหลวหรือ timeout แต่ในความเป็นจริง Vercel ทำหน้าที่แค่รัน function ตาม request ที่เข้ามาแล้วส่ง response กลับไปเท่านั้น ไม่มีกลไก retry ฝั่ง Vercel เองสำหรับ invocation ที่ล้มเหลว
ผู้ที่ตัดสินใจว่าจะ retry หรือไม่คือฝั่งผู้ส่ง webhook เข้ามา ถ้าผู้ส่งไม่ได้รับ response ที่ถือว่าสำเร็จภายในเวลาที่กำหนด ผู้ส่งจะตัดสินใจส่ง event เดิมซ้ำเข้ามาเองตามนโยบายของแต่ละราย ซึ่งบางรายไม่มีนโยบาย retry เลย ถ้า request ล้มเหลวแล้ว event นั้นอาจหายไปเลยโดยไม่มีใครแจ้งเตือน
ผลที่ตามมาคือทีมต้องออกแบบสองเรื่องคู่กัน คือทำให้ function ตอบ response สำเร็จให้ได้มากที่สุดเท่าที่จะทำได้เพื่อไม่ให้ต้องพึ่งพา retry จากผู้ส่ง และมีระบบ monitoring แยกต่างหากที่ตรวจจับได้เองถ้า webhook endpoint เริ่มมี error หรือ timeout สูงผิดปกติ ไม่ใช่รอให้ผู้ส่ง webhook มาแจ้งปัญหาก่อนถึงจะรู้ตัว
Idempotency บน Vercel Function ต้องพึ่ง Storage ภายนอกเสมอ
เพราะ Vercel Function เป็น serverless ที่ instance แต่ละตัวไม่มี state ค้างระหว่าง request ต่อกัน การเก็บสถานะว่า event ไหนเคยประมวลผลไปแล้วบ้างต้องพึ่ง storage ภายนอกเสมอ ไม่สามารถเก็บไว้ใน memory ของ function แล้วหวังว่า instance เดิมจะรับ request ถัดไปได้ เพราะ Vercel อาจสร้าง instance ใหม่รับ request แต่ละครั้งโดยไม่รับประกันว่าจะเป็น instance เดิม
ตัวเลือก storage ที่ใช้กันจริงมีหลายแบบ เช่น Vercel KV สำหรับเก็บสถานะแบบ key-value ที่อ่านเร็ว หรือฐานข้อมูลอย่าง Supabase Postgres ที่ใช้ unique constraint ช่วยกัน event ซ้ำที่ระดับฐานข้อมูลเอง ซึ่งเป็นแนวทางเดียวกับที่ใช้ได้ผลบน Supabase Edge Functions ตามที่อธิบายไว้ในบทความ สร้าง Webhook ด้วย Supabase Edge Functions ทีมที่ใช้ทั้ง Vercel และ Supabase อยู่แล้วในระบบเดียวกันสามารถใช้ตารางเดียวกันนี้เก็บสถานะ idempotency ของ webhook จากหลายแหล่งได้
จุดสำคัญคือต้องเขียนโค้ดตรวจสอบและบันทึกสถานะให้ทนต่อ race condition เมื่อมี retry สอง request เข้ามาพร้อมกัน ไม่ใช่แค่ตรวจสอบก่อนแล้วค่อยเขียนแยกสองขั้นตอนธรรมดา เพราะช่วงเวลาสั้น ๆ ระหว่างสองขั้นตอนนั้นอาจมี request อื่นแทรกเข้ามาได้เสมอในสภาพแวดล้อม serverless ที่ scale ขึ้นหลาย instance พร้อมกัน
- รับ identifier เฉพาะตัวของ event จาก header หรือ payload ก่อนทำงานอื่น
- พยายามบันทึก identifier นี้ลง storage ภายนอกด้วยคำสั่งที่ป้องกันการเขียนซ้ำในตัว เช่น unique constraint หรือ atomic operation
- ถ้าบันทึกสำเร็จ แสดงว่าเป็น event ใหม่ ให้ประมวลผลต่อตามปกติ
- ถ้าบันทึกไม่สำเร็จเพราะ identifier นี้มีอยู่แล้ว แสดงว่าเป็น retry ของ event เดิม ให้ตอบ response สำเร็จกลับไปทันทีโดยไม่ทำงานซ้ำ
ตอบเร็วโดยไม่บล็อก Client ด้วยการแยกงานหลังตอบ Response
เช่นเดียวกับแนวทางที่ใช้ได้ผลบน serverless platform อื่น การแยกงานที่ไม่จำเป็นต้องเสร็จก่อนตอบ response ออกไปทำหลังตอบแล้ว ช่วยลดเวลาที่ผู้ส่ง webhook ต้องรอได้มาก Vercel Function รองรับการสั่งงานที่ทำต่อในพื้นหลังหลังตอบ response ไปแล้ว ทำให้สามารถตอบสำเร็จกลับไปหาผู้ส่งได้ทันทีที่ตรวจสอบและบันทึก event เสร็จ แล้วค่อยทำงานที่เหลือต่อโดยผู้ส่งไม่ต้องรอ
ข้อควรระวังที่เหมือนกับ platform อื่นคืองานที่ทำหลังตอบ response แล้วต้องมีระบบตรวจสอบความสำเร็จของตัวเอง เพราะผู้ส่ง webhook จะไม่รู้เลยถ้างานพื้นหลังนั้นล้มเหลว ควรมี log หรือ alert แยกต่างหากสำหรับตรวจสอบ ไม่ใช่ปล่อยให้ error เงียบหายไปเฉย ๆ โดยไม่มีใครสังเกตเห็น
สำหรับ webhook ที่ต้องประมวลผลข้อมูลจำนวนมากต่อ event เช่นไฟล์แนบขนาดใหญ่ ควรพิจารณาส่งต่อไปเข้า queue ภายนอกแทนการพยายามทำทุกอย่างในงานพื้นหลังของ function เดียว เพราะแม้จะแยกออกจากเส้นทางตอบ response แล้ว ก็ยังมีเพดานเวลาทำงานรวมของ function อยู่ดีไม่ว่าจะทำก่อนหรือหลังตอบ response ก็ตาม
ตารางเทียบ Node.js Serverless Function กับ Edge Function สำหรับรับ Webhook
สรุปความต่างที่สำคัญที่สุดสำหรับใช้ตัดสินใจเลือก function ประเภทไหนสำหรับ webhook receiver
| ประเด็น | Node.js Serverless Function | Edge Function |
|---|---|---|
| Node API เฉพาะทาง | ใช้ได้เต็มรูปแบบ | ใช้ได้จำกัด ต้องเช็ค compatibility |
| ความเร็วในการเริ่มทำงาน (cold start) | ช้ากว่าเล็กน้อยเพราะ container หนักกว่า | เร็วกว่าเพราะ isolate เบากว่า |
| เหมาะกับ Logic แบบไหน | logic ซับซ้อนหรือใช้ library เฉพาะทางของ Node | logic เบา เน้นตอบเร็วเป็นหลัก |
| ตรวจ Signature ด้วย Web Crypto API | ทำได้ผ่าน Node crypto module เช่นกัน | ทำได้ผ่าน Web Crypto API มาตรฐาน |
ตัวอย่างสมมติ: Webhook ล้มเหลวเงียบ ๆ เพราะเวลาทำงานใกล้เพดานพอดี
ลองดูตัวอย่างสมมติของทีมที่สร้าง Node.js Serverless Function รับ webhook จากระบบภายนอก โดย logic ภายในเรียก API ภายในอีกสองตัวต่อกันก่อนตอบ response กลับ ตอนทดสอบในเครื่องและ staging เวลาทำงานรวมอยู่ที่ราวสามในสี่ของเพดานเวลาที่แพ็กเกจกำหนดไว้ ทีมจึงคิดว่าปลอดภัยเพียงพอ (ตัวเลขทั้งหมดเป็นตัวอย่างสมมติเพื่อประกอบการอธิบาย)
พอเข้า production จริง ช่วงที่ API ภายในตัวที่สองมี load สูงกว่าปกติเล็กน้อยเพราะมีงานอื่นเรียกใช้พร้อมกัน เวลาตอบสนองของ API นั้นช้าลงกว่าที่เคยวัดไว้ตอนทดสอบ ทำให้เวลาทำงานรวมของ webhook function เกินเพดานเวลาไปเล็กน้อยในบาง request ผู้ส่ง webhook ที่รอ response ไม่ทันจึงตัดสินใจว่า request นั้นล้มเหลว แต่ทีมพัฒนากลับไม่เห็น error ชัดเจนใน log เพราะ function ยังคงทำงานต่อจนเสร็จอยู่ดี เพียงแต่ตอบ response ไปหลังจากผู้ส่งเลิกรอไปแล้ว
เพราะผู้ส่ง webhook รายนี้ไม่มีนโยบาย retry เมื่อ request ไม่สำเร็จ event ที่เกิดปัญหาจึงหายไปเลยโดยไม่มีใครรู้ตัว จนกว่าจะมีคนสังเกตเห็นว่าข้อมูลบางส่วนหายไปจากรายงานสรุปประจำสัปดาห์ ทีมใช้เวลานานพอสมควรกว่าจะสืบย้อนกลับไปเจอสาเหตุที่แท้จริง
ทีมแก้ปัญหาด้วยการปรับ webhook receiver ให้ตอบ response ทันทีหลังตรวจ signature และบันทึก event เสร็จ แล้วย้ายการเรียก API ภายในทั้งสองตัวไปทำแบบ asynchronous หลังตอบ response พร้อมเพิ่ม monitoring แยกต่างหากที่แจ้งเตือนทันทีถ้ามี event ที่ไม่ถูกประมวลผลให้เสร็จภายในเวลาที่กำหนด ไม่ต้องพึ่งพาการสังเกตด้วยตาจากรายงานสรุปอีกต่อไป
ทำแบบนี้แล้วพัง เพราะอะไร
ข้อผิดพลาดที่พบบ่อยเมื่อทีมสร้าง webhook receiver บน Vercel Function โดยเข้าใจผิดเรื่อง timeout และ retry
- เชื่อว่า Vercel จะ retry การเรียก function ที่ล้มเหลวให้เอง — ทำให้ไม่มีการออกแบบ monitoring หรือ idempotency รองรับ event ที่หายไปเมื่อ function ทำงานไม่ทันเวลา
- เก็บสถานะ idempotency ไว้ใน memory ของ function — ใช้ไม่ได้จริงเพราะ instance ของ serverless function ไม่รับประกันว่าจะเป็นตัวเดิมทุก request
- ทำงานที่ใช้เวลานานทั้งหมดก่อนตอบ response — เพิ่มความเสี่ยงที่เวลาทำงานรวมจะเกินเพดานของแพ็กเกจในช่วงที่ระบบภายนอกตอบสนองช้ากว่าปกติ
- เลือก Edge Function โดยไม่ตรวจ compatibility ของ library ที่ใช้ — เจอ error ตอน build หรือ runtime เพราะ library นั้นพึ่งพา Node API ที่ Edge Function ไม่รองรับ
สรุป
Vercel Function ทั้งสองแบบใช้รับ webhook ได้จริง แต่ต่างกันเรื่อง Node API ที่รองรับและความเร็วในการเริ่มทำงาน ส่วนเรื่อง timeout และ retry เป็นความเข้าใจที่ต้องถูกต้องไม่ว่าจะเลือก function แบบไหน เพราะ Vercel เองไม่ retry ให้ ความรับผิดชอบอยู่ที่การออกแบบ idempotency และ monitoring ของทีมเอง
การแยกงานที่ไม่จำเป็นต้องเสร็จก่อนตอบ response ออกไปทำหลังตอบแล้ว ช่วยลดความเสี่ยงเรื่อง timeout ได้มาก แต่ต้องมีระบบตรวจสอบความสำเร็จของงานพื้นหลังควบคู่กันไปเสมอ ไม่ใช่แค่แยกงานออกไปแล้วปล่อยผ่าน
- Vercel ไม่ retry function ที่ล้มเหลวเอง ต้องออกแบบ idempotency และ monitoring เอง
- เก็บสถานะ idempotency ผ่าน storage ภายนอกเสมอ ไม่พึ่ง memory ของ function
- แยกงานหนักออกจากเส้นทางตอบ response หลัก เพื่อลดความเสี่ยงเกินเพดานเวลาของแพ็กเกจ
คำถามที่พบบ่อย
Vercel retry การเรียก function ที่ timeout ให้อัตโนมัติไหม
ไม่ Vercel ไม่มีกลไก retry การเรียก function เองถ้าล้มเหลวหรือ timeout ความรับผิดชอบเรื่อง retry อยู่ที่ผู้ส่ง webhook ซึ่งบางรายอาจไม่มีนโยบาย retry เลยด้วยซ้ำ
ควรเลือก Node.js Serverless Function หรือ Edge Function สำหรับ webhook
ขึ้นกับ logic ที่ต้องทำ ถ้าต้องใช้ library เฉพาะทางของ Node หรือ logic ซับซ้อน ใช้ Node.js Serverless Function ถ้า logic เบาและเน้นตอบเร็ว Edge Function อาจได้เปรียบเรื่อง cold start
เก็บสถานะ idempotency ไว้ที่ไหนดีบน Vercel
ต้องใช้ storage ภายนอกเสมอ เช่น Vercel KV หรือฐานข้อมูลที่มี unique constraint ช่วยกัน event ซ้ำ ไม่สามารถเก็บไว้ใน memory ของ function ได้เพราะ instance ไม่คงที่
เพดานเวลาทำงานของ Vercel Function เท่ากันทุกแพ็กเกจไหม
ไม่เท่ากัน แพ็กเกจฟรีมีเพดานสั้นกว่าแพ็กเกจที่เสียเงิน และ Edge Function กับ Node.js Serverless Function ในแพ็กเกจเดียวกันก็อาจมีเพดานต่างกันด้วย ควรตรวจค่าจริงของแพ็กเกจที่ใช้อยู่
ทำงานหลังตอบ response แล้ว ถ้าล้มเหลวจะรู้ได้ยังไง
ต้องมีระบบ log หรือ alert แยกต่างหากตรวจสอบความสำเร็จของงานพื้นหลัง เพราะผู้ส่ง webhook ได้รับ response สำเร็จไปแล้วจะไม่มีทางรู้ว่างานหลังจากนั้นล้มเหลว
ต้องใช้ queue ภายนอกเสมอไหมเมื่อรับ webhook บน Vercel
ไม่จำเป็นเสมอไป ถ้างานหลังตรวจ signature เบาและเสร็จเร็ว ทำแบบ asynchronous ในงานพื้นหลังของ function เดียวก็เพียงพอ แต่ถ้าต้องประมวลผลข้อมูลจำนวนมากต่อ event ควรพิจารณาส่งต่อเข้า queue แยกต่างหาก
ลองตรวจด้วยตัวเอง
LINE Webhook Payload Inspector
วาง JSON payload จาก LINE แล้วดูว่าเป็น event ชนิดไหน มี field ครบตาม schema ปัจจุบันหรือไม่
ตรวจ payload ฟรี →ใช้ฟรี ไม่ต้องสมัคร ไม่เก็บข้อมูลที่คุณกรอก
อ่านต่อแบบเจาะลึก
วัด Conversion LINE ทุกแบรนด์ รวมศูนย์ที่เดียว
องค์กรที่มีหลายแบรนด์ หลายสาขา หลาย LINE OA — linli รวม Tracking และส่ง Conversion กลับทุกแพลตฟอร์ม พร้อม Custom Limit เริ่มฟรี 14 วัน
ติดต่อทีม Salesบทความที่เกี่ยวข้อง

ทำไม LINE Webhook ที่ตรวจ Signature ถูกแล้วยังโดน Cloudflare Workers ปฏิเสธ

ทราฟฟิกพุ่งกลางดึกแต่ Cloudflare Workers เชื่อม Supabase Postgres ไว้ทัน แก้ยังไง
