เอกสารนี้อธิบายวิธีขอฟังก์ชันพื้นหลังแบบอะซิงโครนัส (ที่ไม่ใช่ HTTPS) ให้ลองอีกครั้งเมื่อล้มเหลว
เหตุใดฟังก์ชันที่ขับเคลื่อนด้วยเหตุการณ์จึงทำงานไม่สำเร็จ
ในบางครั้ง ฟังก์ชันอาจหยุดทำงานก่อนเวลาอันควรเนื่องจากเกิดข้อผิดพลาดภายใน และโดยค่าเริ่มต้น ระบบอาจลองเรียกใช้ฟังก์ชันอีกครั้งโดยอัตโนมัติหรือไม่ก็ได้
โดยปกติแล้ว ฟังก์ชันที่ขับเคลื่อนด้วยเหตุการณ์อาจทำงานไม่สำเร็จเนื่องจากข้อผิดพลาดที่เกิดขึ้นในโค้ดของฟังก์ชันเอง สาเหตุที่อาจเกิด ขึ้นมีดังนี้
- ฟังก์ชันมีข้อบกพร่องและรันไทม์จะส่งข้อยกเว้น
- ฟังก์ชันเข้าถึงปลายทางของบริการไม่ได้ หรือหมดเวลาขณะพยายามเข้าถึง
- ฟังก์ชันจะตั้งใจส่งข้อยกเว้น (เช่น เมื่อพารามิเตอร์ ไม่ผ่านการตรวจสอบ)
- ฟังก์ชัน Node.js จะแสดงผล Promise ที่ถูกปฏิเสธ หรือส่งค่าที่ไม่ใช่
nullไปยัง Callback
ในกรณีใดก็ตามข้างต้น ฟังก์ชันจะหยุดดำเนินการและแสดงผลข้อผิดพลาด ทริกเกอร์เหตุการณ์ที่สร้างข้อความมีนโยบายการลองใหม่ที่คุณปรับแต่งได้ เพื่อให้ตรงกับความต้องการของฟังก์ชัน
ความหมายของการลองอีกครั้ง
Cloud Functions จะดำเนินการฟังก์ชันที่ขับเคลื่อนด้วยเหตุการณ์อย่างน้อย 1 ครั้ง สำหรับแต่ละเหตุการณ์ที่แหล่งเหตุการณ์ปล่อยออกมา โดยค่าเริ่มต้น หากการเรียกใช้ฟังก์ชัน สิ้นสุดลงด้วยข้อผิดพลาด ระบบจะไม่เรียกใช้ฟังก์ชันอีกครั้งและจะทิ้ง เหตุการณ์ เมื่อเปิดใช้การลองใหม่ในฟังก์ชันที่ขับเคลื่อนด้วยเหตุการณ์ Cloud Functions จะลองเรียกใช้ฟังก์ชันที่ล้มเหลวอีกครั้งจนกว่าจะเสร็จสมบูรณ์ สำเร็จหรือช่วงการลองใหม่หมดอายุ
เมื่อไม่ได้เปิดใช้การลองใหม่สำหรับฟังก์ชัน ซึ่งเป็นค่าเริ่มต้น ฟังก์ชันจะรายงานเสมอว่าทำงานสำเร็จ และโค้ดตอบกลับ 200 OK อาจปรากฏในบันทึก ซึ่งจะเกิดขึ้นแม้ว่าฟังก์ชันจะพบข้อผิดพลาดก็ตาม หากต้องการให้ชัดเจนเมื่อฟังก์ชันพบข้อผิดพลาด โปรดรายงานข้อผิดพลาดอย่างเหมาะสม
กำหนดค่าการลองใหม่จากโค้ดฟังก์ชัน
Cloud Functions for Firebase ช่วยให้คุณเปิดใช้การลองใหม่ในโค้ดสำหรับฟังก์ชันได้ หากต้องการดำเนินการนี้สำหรับเหตุการณ์เบื้องหลัง เช่น การสร้างเอกสาร Firestore ใหม่
ให้ตั้งค่าตัวเลือกนโยบาย failurePolicy (รุ่นที่ 1) หรือ retry (รุ่นที่ 2) เป็น true
รุ่นที่ 1
exports.docCreated = functions
.runWith({
// retry on failure
failurePolicy: true,
})
.firestore.document("my-collection/{docId}")
.onCreate((change, context) => {
/* ... */
});
รุ่นที่ 2
const { onDocumentCreated } = require("firebase-functions/firestore");
exports.docCreated = onDocumentCreated(
{
// retry on failure
retry: true,
},
"my-collection/{docId}",
(event) => {
/* ... */
},
);
การตั้งค่า true ตามที่แสดงจะกำหนดค่าฟังก์ชันให้ลองอีกครั้งเมื่อล้มเหลว
กรอบเวลาลองอีกครั้ง
สำหรับฟังก์ชันรุ่นที่ 2 กรอบเวลาลองอีกครั้งนี้จะหมดอายุหลังจาก 24 ชั่วโมง สำหรับฟังก์ชันรุ่นที่ 1 ฟังก์ชันจะหมดอายุ หลังจากผ่านไป 7 วัน Cloud Functions จะลองเรียกใช้ฟังก์ชันที่ขับเคลื่อนด้วยเหตุการณ์ที่สร้างขึ้นใหม่โดยใช้ กลยุทธ์ Exponential Backoff โดยจะเพิ่มการหยุดชั่วคราวระหว่าง 10 ถึง 600 วินาที นโยบายนี้จะมีผลกับฟังก์ชันใหม่ ในครั้งแรกที่คุณติดตั้งใช้งาน การเปลี่ยนแปลงนี้จะไม่มีผลย้อนหลังกับฟังก์ชันที่มีอยู่ ซึ่งมีการติดตั้งใช้งานครั้งแรกก่อนที่การเปลี่ยนแปลงที่อธิบายไว้ในหมายเหตุประจำรุ่นนี้ จะมีผล แม้ว่าคุณจะติดตั้งใช้งานฟังก์ชันอีกครั้งก็ตามแนวทางปฏิบัติแนะนำ
ส่วนนี้จะอธิบายแนวทางปฏิบัติแนะนำสำหรับการใช้การลองใหม่
ใช้การลองอีกครั้งเพื่อจัดการข้อผิดพลาดแบบชั่วคราว
เนื่องจากระบบจะลองเรียกใช้ฟังก์ชันของคุณซ้ำอย่างต่อเนื่องจนกว่าจะดำเนินการสำเร็จ คุณจึงควรแก้ไขข้อผิดพลาดถาวร เช่น บั๊ก ในโค้ดผ่านการทดสอบ ก่อนที่จะเปิดใช้การลองใหม่ การลองใหม่เหมาะที่สุดสำหรับจัดการความล้มเหลวเป็นระยะๆ หรือชั่วคราว ซึ่งมีแนวโน้มสูงที่จะแก้ไขได้เมื่อลองใหม่ เช่น ปลายทางบริการที่ไม่เสถียรหรือหมดเวลา
กำหนดเงื่อนไขสิ้นสุดเพื่อหลีกเลี่ยงการวนซ้ำของการลองใหม่แบบไม่สิ้นสุด
แนวทางปฏิบัติแนะนำคือการป้องกันฟังก์ชันไม่ให้วนซ้ำอย่างต่อเนื่องเมื่อ ใช้การลองใหม่ คุณทำได้โดยระบุเงื่อนไขสิ้นสุดที่กำหนดไว้อย่างชัดเจน ก่อนที่ฟังก์ชันจะเริ่มประมวลผล โปรดทราบว่าเทคนิคนี้จะใช้ได้ก็ต่อเมื่อ ฟังก์ชันของคุณเริ่มทำงานได้สำเร็จและประเมินเงื่อนไขสิ้นสุดได้
แนวทางที่เรียบง่ายแต่มีประสิทธิภาพคือการทิ้งเหตุการณ์ที่มีการประทับเวลาเก่ากว่า เวลาที่กำหนด ซึ่งจะช่วยหลีกเลี่ยงการดำเนินการมากเกินไปเมื่อเกิดข้อผิดพลาด อย่างต่อเนื่องหรือนานกว่าที่คาดไว้
เช่น ข้อมูลโค้ดนี้จะทิ้งเหตุการณ์ทั้งหมดที่เก่ากว่า 10 วินาที
const eventAgeMs = Date.now() - Date.parse(event.timestamp);
const eventMaxAgeMs = 10000;
if (eventAgeMs > eventMaxAgeMs) {
console.log(`Dropping event ${event} with age[ms]: ${eventAgeMs}`);
callback();
return;
}
ใช้ catch กับ Promise
หากฟังก์ชันเปิดใช้การลองใหม่ ข้อผิดพลาดที่ไม่ได้จัดการจะทําให้เกิดการลองใหม่ ตรวจสอบว่าโค้ดจับข้อผิดพลาดที่ไม่ควรทำให้เกิดการลองใหม่
ตัวอย่างสิ่งที่คุณควรทำมีดังนี้
return doFooAsync().catch((err) => {
if (isFatal(err)) {
console.error(`Fatal error ${err}`);
}
return Promise.reject(err);
});
ทำให้ฟังก์ชันที่ขับเคลื่อนด้วยเหตุการณ์ที่ลองใหม่ได้เป็นแบบไอดีมโพเทนต์
ฟังก์ชันที่ขับเคลื่อนด้วยเหตุการณ์ซึ่งลองอีกครั้งได้ต้องเป็นฟังก์ชันที่ไม่มีผลข้างเคียง ต่อไปนี้คือ หลักเกณฑ์ทั่วไปในการทำให้ฟังก์ชันดังกล่าวเป็นฟังก์ชันที่ไม่มีผลข้างเคียง
- API ภายนอกหลายรายการ (เช่น Stripe) อนุญาตให้คุณระบุคีย์การดำเนินการซ้ำ เป็นพารามิเตอร์ หากคุณใช้ API ดังกล่าว คุณควรใช้รหัสเหตุการณ์เป็นคีย์การดำเนินการแบบไอดีมโปเทนซี
- การดำเนินการแบบ Idempotent ทำงานได้ดีกับการนำส่งแบบ "อย่างน้อย 1 ครั้ง" เนื่องจากทำให้การลองใหม่ปลอดภัย ดังนั้นแนวทางปฏิบัติแนะนำทั่วไปในการเขียนโค้ดที่เชื่อถือได้คือการรวม การดำเนินการซ้ำกับความสามารถในการดำเนินการซ้ำ
- ตรวจสอบว่าโค้ดของคุณเป็น Idempotent ภายใน เช่น
- ตรวจสอบว่าการเปลี่ยนแปลงเกิดขึ้นได้มากกว่า 1 ครั้งโดยไม่เปลี่ยน ผลลัพธ์
- ค้นหาสถานะฐานข้อมูลในธุรกรรมก่อนที่จะเปลี่ยนสถานะ
- ตรวจสอบว่าผลข้างเคียงทั้งหมดเป็นแบบ Idempotent
- กำหนดการตรวจสอบธุรกรรมภายนอกฟังก์ชันโดยไม่ขึ้นอยู่กับโค้ด เช่น ให้บันทึกสถานะไว้ที่ใดที่หนึ่งเพื่อบันทึกว่ามีการประมวลผลรหัสเหตุการณ์ที่ระบุแล้ว
- จัดการการเรียกใช้ฟังก์ชันที่ซ้ำกันนอกแบนด์ เช่น มีกระบวนการล้างข้อมูลแยกต่างหาก ซึ่งจะล้างข้อมูลหลังจากการเรียกฟังก์ชันที่ซ้ำกัน
กำหนดค่านโยบายการลองใหม่
คุณอาจต้องการกำหนดค่านโยบายการลองใหม่โดยตรง ทั้งนี้ขึ้นอยู่กับความต้องการของฟังก์ชัน ซึ่งจะช่วยให้คุณตั้งค่าการผสมผสานใดๆ ต่อไปนี้ได้
- ลดกรอบเวลาลองอีกครั้งจาก 7 วันเหลือเพียง 10 นาที
- เปลี่ยนเวลาหยุดชั่วคราวขั้นต่ำและสูงสุดสำหรับกลยุทธ์การลองใหม่แบบ Exponential Backoff
- เปลี่ยนกลยุทธ์การลองใหม่เป็นการลองใหม่ทันที
- กำหนดค่าหัวข้อจดหมายที่ส่งไม่ได้
- กำหนดจำนวนครั้งสูงสุดและต่ำสุดในการพยายามนำส่ง
วิธีกำหนดค่านโยบายการลองใหม่
- เขียนฟังก์ชัน HTTP
- ใช้ Pub/Sub API เพื่อสร้างPub/Subการสมัครใช้บริการ โดยระบุ URL ของ ฟังก์ชันเป็นเป้าหมาย
ดูข้อมูลเพิ่มเติมเกี่ยวกับการกำหนดค่า Pub/Sub โดยตรงได้ในเอกสารประกอบของ Pub/Sub เกี่ยวกับการจัดการความล้มเหลว