เอกสารนี้อธิบายวิธีขอให้ฟังก์ชันเบื้องหลังแบบอะซิงโครนัส (ที่ไม่ใช่ HTTPS) ลองใหม่เมื่อล้มเหลว
เหตุใดฟังก์ชันที่ขับเคลื่อนด้วยเหตุการณ์จึงทำงานไม่เสร็จสมบูรณ์
ในบางครั้ง ฟังก์ชันอาจหยุดทำงานก่อนเวลาอันควรเนื่องจากข้อผิดพลาดภายใน และโดยค่าเริ่มต้น ระบบอาจลองใหม่กับฟังก์ชันโดยอัตโนมัติหรือไม่ก็ได้
โดยปกติแล้ว ฟังก์ชันที่ขับเคลื่อนด้วยเหตุการณ์อาจทำงานไม่สำเร็จเนื่องจากข้อผิดพลาดที่เกิดขึ้นในโค้ดของฟังก์ชันเอง สาเหตุที่อาจทำให้เกิดเหตุการณ์นี้ ได้แก่
- ฟังก์ชันมีข้อบกพร่องและรันไทม์แสดงข้อยกเว้น
- ฟังก์ชันไม่สามารถเข้าถึงปลายทางของบริการหรือหมดเวลาขณะพยายามเข้าถึง
- ฟังก์ชันแสดงข้อยกเว้นโดยเจตนา (เช่น เมื่อพารามิเตอร์ไม่ผ่านการตรวจสอบ)
- ฟังก์ชัน Node.js แสดงผลสัญญาที่ถูกปฏิเสธ หรือส่งค่าที่ไม่ใช่
nullไปยัง Callback
ในกรณีใดกรณีหนึ่งข้างต้น ฟังก์ชันจะหยุดการทำงานและแสดงข้อผิดพลาด ทริกเกอร์เหตุการณ์ที่สร้างข้อความมีนโยบายการลองใหม่ที่คุณปรับแต่งให้ตรงกับความต้องการของฟังก์ชันได้
ความหมายของการลองใหม่
Cloud Functions จะเรียกใช้ฟังก์ชันที่ขับเคลื่อนด้วยเหตุการณ์อย่างน้อย 1 ครั้ง สำหรับแต่ละเหตุการณ์ที่แหล่งที่มาของเหตุการณ์ปล่อยออกมา โดยค่าเริ่มต้น หากการเรียกใช้ฟังก์ชันสิ้นสุดลงด้วยข้อผิดพลาด ระบบจะไม่เรียกใช้ฟังก์ชันอีกครั้งและจะทิ้งเหตุการณ์นั้น เมื่อคุณเปิดใช้การลองใหม่ในฟังก์ชันที่ขับเคลื่อนด้วยเหตุการณ์ Cloud Functions จะลองเรียกใช้ฟังก์ชันที่ล้มเหลวอีกครั้งจนกว่าจะทำงานเสร็จสมบูรณ์ หรือระยะเวลาการลองใหม่หมดลง
เมื่อไม่ได้เปิดใช้การลองใหม่สำหรับฟังก์ชัน (ซึ่งเป็นค่าเริ่มต้น) ฟังก์ชันจะรายงานเสมอว่าทำงานสำเร็จ และโค้ดตอบกลับ 200 OK อาจปรากฏในบันทึก ซึ่งจะเกิดขึ้นแม้ว่าฟังก์ชันจะพบข้อผิดพลาดก็ตาม โปรดรายงานข้อผิดพลาดอย่างเหมาะสมเพื่อให้ทราบอย่างชัดเจนเมื่อฟังก์ชันพบข้อผิดพลาด
กำหนดค่าการลองใหม่จากโค้ดของฟังก์ชัน
With Cloud Functions for Firebase, คุณสามารถเปิดใช้การลองใหม่ในโค้ดสำหรับa
ฟังก์ชันได้ หากต้องการดำเนินการนี้สำหรับเหตุการณ์เบื้องหลัง เช่น การสร้างเอกสาร 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 โดยจะเพิ่มระยะเวลา 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 กับสัญญา
หากฟังก์ชันเปิดใช้การลองใหม่ไว้ ข้อผิดพลาดที่ไม่ได้จัดการจะทริกเกอร์การลองใหม่ ตรวจสอบว่าโค้ดของคุณดักจับข้อผิดพลาดที่ไม่ควรทำให้เกิดการลองใหม่
ตัวอย่างสิ่งที่คุณควรทำมีดังนี้
return doFooAsync().catch((err) => {
if (isFatal(err)) {
console.error(`Fatal error ${err}`);
}
return Promise.reject(err);
});
ทำให้ฟังก์ชันที่ขับเคลื่อนด้วยเหตุการณ์ที่ลองใหม่ได้เป็นฟังก์ชันที่ทำงานซ้ำได้
ฟังก์ชันที่ขับเคลื่อนด้วยเหตุการณ์ที่ลองใหม่ได้ต้องเป็นฟังก์ชันที่ทำงานซ้ำได้ ต่อไปนี้คือหลักเกณฑ์ทั่วไปสำหรับการทำให้ฟังก์ชันดังกล่าวเป็นฟังก์ชันที่ทำงานซ้ำได้
- API ภายนอกหลายรายการ (เช่น Stripe) ให้คุณระบุคีย์การทำงานซ้ำได้เป็นพารามิเตอร์ หากคุณใช้ API ดังกล่าว คุณควรใช้รหัสเหตุการณ์เป็นคีย์การทำงานซ้ำได้
- การทำงานซ้ำได้ทำงานได้ดีกับการส่งอย่างน้อย 1 ครั้ง เนื่องจากทำให้การลองใหม่ปลอดภัย ดังนั้นแนวทางปฏิบัติแนะนำทั่วไปสำหรับการเขียนโค้ดที่เชื่อถือได้คือการรวมการทำงานซ้ำได้กับการลองใหม่
- ตรวจสอบว่าโค้ดของคุณทำงานซ้ำได้ภายใน ตัวอย่างเช่น
- ตรวจสอบว่าการเปลี่ยนแปลงเกิดขึ้นได้มากกว่า 1 ครั้งโดยไม่เปลี่ยนผลลัพธ์
- ค้นหาสถานะฐานข้อมูลในธุรกรรมก่อนที่จะเปลี่ยนสถานะ
- ตรวจสอบว่าผลข้างเคียงทั้งหมดทำงานซ้ำได้
- กำหนดการตรวจสอบธุรกรรมภายนอกฟังก์ชันโดยไม่ขึ้นอยู่กับโค้ด เช่น เก็บสถานะไว้ที่ใดที่หนึ่งเพื่อบันทึกว่ามีการประมวลผลรหัสเหตุการณ์ที่กำหนดแล้ว
- จัดการกับการเรียกใช้ฟังก์ชันที่ซ้ำกันนอกแบนด์ เช่น มีกระบวนการล้างข้อมูลแยกต่างหากที่ล้างข้อมูลหลังจากการเรียกใช้ฟังก์ชันที่ซ้ำกัน
กำหนดค่านโยบายการลองใหม่
คุณอาจต้องกำหนดค่านโยบายการลองใหม่โดยตรง ทั้งนี้ขึ้นอยู่กับความต้องการของฟังก์ชัน ซึ่งจะช่วยให้คุณตั้งค่าการผสมผสานใดๆ ต่อไปนี้ได้
- ลดระยะเวลาการลองใหม่จาก 7 วันเหลือเพียง 10 นาที
- เปลี่ยนระยะเวลา Backoff ต่ำสุดและสูงสุดสำหรับกลยุทธ์การลองใหม่แบบ Exponential Backoff
- เปลี่ยนกลยุทธ์การลองใหม่ให้ลองใหม่ทันที
- กำหนดค่าหัวข้อ Dead-Letter
- กำหนดจำนวนการพยายามส่งสูงสุดและต่ำสุด
วิธีกำหนดค่านโยบายการลองใหม่
- เขียนฟังก์ชัน HTTP
- ใช้ Pub/Sub API เพื่อสร้างการสมัครใช้บริการ Pub/Sub โดยระบุ URL ของ ฟังก์ชันเป็นเป้าหมาย
ดูข้อมูลเพิ่มเติมเกี่ยวกับการกำหนดค่า Pub/Sub โดยตรงได้ในเอกสารประกอบของ Pub/Sub เกี่ยวกับการจัดการกับความล้มเหลว