แอปที่ใช้ฟังก์ชันรุ่นที่ 1 ควรพิจารณาย้ายข้อมูลไปยังรุ่นที่ 2 โดยใช้คำแนะนำในคู่มือนี้ ฟังก์ชันรุ่นที่ 2 ใช้ Cloud Run เพื่อมอบประสิทธิภาพ การกำหนดค่า การตรวจสอบที่ดีขึ้น และอื่นๆ
ตัวอย่างในหน้านี้จะถือว่าคุณใช้ JavaScript กับโมดูล CommonJS (การนำเข้าสไตล์ require) แต่หลักการเดียวกันนี้ใช้ได้กับ JavaScript ที่มี ESM (การนำเข้าสไตล์ import … from) และ TypeScript
กระบวนการย้ายข้อมูล
ฟังก์ชันรุ่นที่ 1 และรุ่นที่ 2 สามารถอยู่ร่วมกันในไฟล์เดียวกันได้ ซึ่งช่วยให้ย้ายข้อมูลทีละส่วนได้ง่ายเมื่อคุณพร้อม เราขอแนะนำให้ย้ายข้อมูลฟังก์ชันทีละรายการ ทำการทดสอบและยืนยันก่อนดำเนินการต่อ
ตรวจสอบ Firebase CLI และเวอร์ชัน firebase-function
ตรวจสอบว่าคุณใช้ Firebase CLI เวอร์ชัน 12.00 และ firebase-functions เวอร์ชัน 4.3.0 ขึ้นไป เวอร์ชันใหม่กว่าจะรองรับทั้งรุ่นที่ 2 และรุ่นที่ 1
อัปเดตการนำเข้า
ฟังก์ชันรุ่นที่ 2 จะนำเข้าจากแพ็กเกจย่อย v2 ใน SDK firebase-functions
เส้นทางการนำเข้าที่แตกต่างกันนี้เป็นข้อมูลทั้งหมดที่ Firebase CLI ต้องการเพื่อพิจารณาว่าจะทำให้โค้ดฟังก์ชันใช้งานได้เป็นฟังก์ชันรุ่นที่ 1 หรือรุ่นที่ 2
แพ็กเกจย่อย v2 เป็นแบบแยกส่วน และเราขอแนะนำให้นำเข้าเฉพาะโมดูลที่เฉพาะเจาะจงที่คุณต้องการเท่านั้น
ก่อน: รุ่นที่ 1
const functions = require("firebase-functions/v1");
หลัง: รุ่นที่ 2
// explicitly import each trigger
const {onRequest} = require("firebase-functions/v2/https");
const {onDocumentCreated} = require("firebase-functions/v2/firestore");
อัปเดตคำจำกัดความของทริกเกอร์
เนื่องจาก SDK รุ่นที่ 2 ชอบการนำเข้าแบบแยกส่วน ให้อัปเดตคำจำกัดความของทริกเกอร์เพื่อแสดงการนำเข้าที่เปลี่ยนแปลงจากขั้นตอนก่อนหน้า
อาร์กิวเมนต์ที่ส่งไปยังฟังก์ชัน Callback สำหรับทริกเกอร์บางรายการมีการเปลี่ยนแปลง ในตัวอย่างนี้ โปรดทราบว่าอาร์กิวเมนต์ของฟังก์ชัน Callback onDocumentCreated ได้รับการรวมเป็นออบเจ็กต์ event เดียว นอกจากนี้ ทริกเกอร์บางรายการยังมีฟีเจอร์การกำหนดค่าใหม่ที่สะดวก เช่น ตัวเลือก cors ของทริกเกอร์ onRequest
ก่อน: รุ่นที่ 1
const functions = require("firebase-functions/v1");
exports.date = functions.https.onRequest((req, res) => {
// ...
});
exports.uppercase = functions.firestore
.document("my-collection/{docId}")
.onCreate((change, context) => {
// ...
});
หลัง: รุ่นที่ 2
const {onRequest} = require("firebase-functions/v2/https");
const {onDocumentCreated} = require("firebase-functions/v2/firestore");
exports.date = onRequest({cors: true}, (req, res) => {
// ...
});
exports.uppercase = onDocumentCreated("my-collection/{docId}", (event) => {
/* ... */
});
ใช้การกำหนดค่าแบบพารามิเตอร์
ฟังก์ชันรุ่นที่ 2 จะเลิกใช้ functions.config และหันมาใช้อินเทอร์เฟซที่ปลอดภัยยิ่งขึ้น
เพื่อ กำหนดพารามิเตอร์การกำหนดค่าแบบประกาศ
ภายในฐานของโค้ด
ด้วยโมดูล params ใหม่ CLI จะบล็อกการทำให้ใช้งานได้ เว้นแต่ว่าพารามิเตอร์ทั้งหมดจะมีค่าที่ถูกต้อง เพื่อให้มั่นใจว่าจะไม่มีการทำให้ฟังก์ชันใช้งานได้โดยไม่มีการกำหนดค่า
ก่อน: รุ่นที่ 1
const functions = require("firebase-functions/v1");
exports.getQuote = functions.https.onRequest(async (req, res) => {
const quote = await fetchMotivationalQuote(functions.config().apiKey);
// ...
});
หลัง: รุ่นที่ 2
const {onRequest} = require("firebase-functions/v2/https");
const {defineSecret} = require("firebase-functions/params");
// Define the secret parameter
const apiKey = defineSecret("API_KEY");
exports.getQuote = onRequest(
// make the secret available to this function
{ secrets: [apiKey] },
async (req, res) => {
// retrieve the value of the secret
const quote = await fetchMotivationalQuote(apiKey.value());
// ...
}
);
หากคุณมีการกำหนดค่าสภาพแวดล้อมที่มีอยู่ด้วย functions.config ให้ย้ายข้อมูลการกำหนดค่านี้เป็นส่วนหนึ่งของการอัปเกรดเป็นรุ่นที่ 2
API functions.config เลิกใช้งานแล้วและจะหยุดให้บริการในเดือนมีนาคม 2027
หลังจากวันที่ดังกล่าว การทำให้ใช้งานได้ด้วย functions.config จะล้มเหลว
หากต้องการป้องกันไม่ให้การทำให้ใช้งานได้ล้มเหลว ให้ย้ายข้อมูลการกำหนดค่าไปยัง Cloud Secret Manager โดยใช้ Firebase CLI เราขอแนะนำอย่างยิ่งให้ใช้วิธีนี้เนื่องจากเป็นวิธีที่มีประสิทธิภาพและปลอดภัยที่สุดในการย้ายข้อมูลการกำหนดค่า
ส่งออกการกำหนดค่าด้วย Firebase CLI
ใช้คำสั่ง
config exportเพื่อส่งออกการกำหนดค่าสภาพแวดล้อมที่มีอยู่ไปยังข้อมูลลับใหม่ใน Cloud Secret Manager$ firebase functions:config:export i This command retrieves your Runtime Config values (accessed via functions.config()) and exports them as a Secret Manager secret. i Fetching your existing functions.config() from your project... ✔ Fetched your existing functions.config(). i Configuration to be exported: ⚠ This may contain sensitive data. Do not share this output. { ... } ✔ What would you like to name the new secret for your configuration? RUNTIME_CONFIG ✔ Created new secret version projects/project/secrets/RUNTIME_CONFIG/versions/1```อัปเดตโค้ดฟังก์ชันเพื่อผูกข้อมูลลับ
หากต้องการใช้การกำหนดค่าที่จัดเก็บไว้ในข้อมูลลับใหม่ใน Cloud Secret Manager ให้ใช้ API
defineJsonSecretในแหล่งที่มาของฟังก์ชัน นอกจากนี้ ตรวจสอบว่าได้ผูกข้อมูลลับกับฟังก์ชันทั้งหมดที่ต้องใช้ก่อน
const functions = require("firebase-functions/v1"); exports.myFunction = functions.https.onRequest((req, res) => { const apiKey = functions.config().someapi.key; // ... });หลัง
const { onRequest } = require("firebase-functions/v2/https"); const { defineJsonSecret } = require("firebase-functions/params"); const config = defineJsonSecret("RUNTIME_CONFIG"); exports.myFunction = onRequest( // Bind secret to your function { secrets: [config] }, (req, res) => { // Access secret values via .value() const apiKey = config.value().someapi.key; // ... });ทำให้ฟังก์ชันใช้งานได้
ทำให้ฟังก์ชันที่อัปเดตแล้วใช้งานได้เพื่อใช้การเปลี่ยนแปลงและผูกสิทธิ์ข้อมูลลับ
firebase deploy --only functions:<your-function-name>
ตั้งค่าตัวเลือกการรันไทม์
การกำหนดค่าตัวเลือกการรันไทม์ มีการเปลี่ยนแปลงระหว่างรุ่นที่ 1 และรุ่นที่ 2 นอกจากนี้ รุ่นที่ 2 ยังเพิ่มความสามารถใหม่ในการ ตั้งค่าตัวเลือกสำหรับฟังก์ชันทั้งหมด
ก่อน: รุ่นที่ 1
const functions = require("firebase-functions/v1");
exports.date = functions
.runWith({
// Keep 5 instances warm for this latency-critical function
minInstances: 5,
})
// locate function closest to users
.region("asia-northeast1")
.https.onRequest((req, res) => {
// ...
});
exports.uppercase = functions
// locate function closest to users and database
.region("asia-northeast1")
.firestore.document("my-collection/{docId}")
.onCreate((change, context) => {
// ...
});
หลัง: รุ่นที่ 2
const {onRequest} = require("firebase-functions/v2/https");
const {onDocumentCreated} = require("firebase-functions/v2/firestore");
const {setGlobalOptions} = require("firebase-functions/v2");
// locate all functions closest to users
setGlobalOptions({ region: "asia-northeast1" });
exports.date = onRequest({
// Keep 5 instances warm for this latency-critical function
minInstances: 5,
}, (req, res) => {
// ...
});
exports.uppercase = onDocumentCreated("my-collection/{docId}", (event) => {
/* ... */
});
อัปเดตบัญชีบริการเริ่มต้น (ไม่บังคับ)
แม้ว่าฟังก์ชันรุ่นที่ 1 จะใช้บัญชีบริการเริ่มต้นของ Google App Engine เพื่อให้สิทธิ์เข้าถึง Firebase API แต่ฟังก์ชันรุ่นที่ 2 จะใช้บัญชีบริการเริ่มต้นของ Compute Engine ความแตกต่างนี้อาจทำให้เกิดปัญหาเกี่ยวกับสิทธิ์สำหรับฟังก์ชันที่ย้ายข้อมูลไปยังรุ่นที่ 2 ในกรณีที่คุณให้สิทธิ์พิเศษแก่บัญชีบริการรุ่นที่ 1 หากคุณไม่ได้เปลี่ยนสิทธิ์ของบัญชีบริการใดๆ คุณสามารถข้ามขั้นตอนนี้ได้
วิธีแก้ปัญหาที่แนะนำคือการกำหนดบัญชีบริการเริ่มต้นของ App Engine รุ่นที่ 1 ที่มีอยู่ให้กับฟังก์ชันที่คุณต้องการย้ายข้อมูลไปยังรุ่นที่ 2 อย่างชัดเจน โดยลบล้างค่าเริ่มต้นของรุ่นที่ 2 คุณทำได้โดยตรวจสอบว่าฟังก์ชันที่ย้ายข้อมูลแต่ละรายการตั้งค่า serviceAccountEmail เป็นค่าที่ถูกต้อง
const {onRequest} = require("firebase-functions/https");
const {onDocumentCreated} = require("firebase-functions/v2/firestore");
const {setGlobalOptions} = require("firebase-functions");
// Use the App Engine default service account for all functions
setGlobalOptions({serviceAccountEmail: '<my-project-number>@<wbr>appspot.gserviceaccount.com'});
// Now I use the App Engine default service account.
exports.date = onRequest({cors: true}, (req, res) => {
// ...
});
// I do too!
exports.uppercase = onDocumentCreated("my-collection/{docId}", (event) => {
// ...
});
อีกวิธีหนึ่งคือตรวจสอบว่าได้แก้ไขรายละเอียดบัญชีบริการให้ตรงกับสิทธิ์ที่จำเป็นทั้งหมดในทั้งบัญชีบริการเริ่มต้นของ App Engine (สำหรับรุ่นที่ 1) และบัญชีบริการเริ่มต้นของ Compute Engine (สำหรับรุ่นที่ 2)
ใช้การทำงานพร้อมกัน
ข้อได้เปรียบที่สำคัญของฟังก์ชันรุ่นที่ 2 คือความสามารถของอินสแตนซ์ฟังก์ชันเดียวในการให้บริการคำขอมากกว่า 1 รายการพร้อมกัน ซึ่งจะช่วยลดจำนวนการเริ่มต้นแบบเย็นที่ผู้ใช้ปลายทางพบได้อย่างมาก โดยค่าเริ่มต้น การทำงานพร้อมกันจะตั้งไว้ที่ 80 แต่คุณสามารถตั้งค่าเป็นค่าใดก็ได้ตั้งแต่ 1 ถึง 1,000
const {onRequest} = require("firebase-functions/v2/https");
exports.date = onRequest({
// set concurrency value
concurrency: 500
},
(req, res) => {
// ...
});
การปรับการทำงานพร้อมกันจะช่วยเพิ่มประสิทธิภาพและลดค่าใช้จ่ายของฟังก์ชัน ดูข้อมูลเพิ่มเติมเกี่ยวกับการเกิดขึ้นพร้อมกันได้ที่ อนุญาตคำขอพร้อมกัน
ตรวจสอบการใช้ตัวแปรส่วนกลาง
ฟังก์ชันรุ่นที่ 1 ที่เขียนขึ้นโดยไม่ได้คำนึงถึงการทำงานพร้อมกันอาจใช้ตัวแปรร่วมที่ตั้งค่าและอ่านในแต่ละคำขอ เมื่อเปิดใช้การทำงานพร้อมกันและอินสแตนซ์เดียวเริ่มจัดการคำขอหลายรายการพร้อมกัน ฟังก์ชันอาจเกิดข้อบกพร่องในฟังก์ชันของคุณเนื่องจากคำขอพร้อมกันเริ่มตั้งค่าและอ่านตัวแปรร่วมพร้อมกัน
ขณะอัปเกรด คุณสามารถตั้งค่า CPU ของฟังก์ชันเป็น gcf_gen1 และตั้งค่า concurrency เป็น 1 เพื่อคืนค่าลักษณะการทำงานของรุ่นที่ 1
const {onRequest} = require("firebase-functions/v2/https");
exports.date = onRequest({
// TEMPORARY FIX: remove concurrency
cpu: "gcf_gen1",
concurrency: 1
},
(req, res) => {
// ...
});
อย่างไรก็ตาม เราไม่แนะนำให้ใช้วิธีนี้เป็นการแก้ไขระยะยาว เนื่องจากจะทำให้เสียข้อได้เปรียบด้านประสิทธิภาพของฟังก์ชันรุ่นที่ 2 ให้ตรวจสอบการใช้ตัวแปรส่วนกลางในฟังก์ชันและนำการตั้งค่าชั่วคราวเหล่านี้ออกเมื่อพร้อม
ย้ายการรับส่งข้อมูลไปยังฟังก์ชันรุ่นที่ 2 ใหม่
เช่นเดียวกับการเปลี่ยนภูมิภาคหรือประเภททริกเกอร์ของฟังก์ชัน คุณจะต้องตั้งชื่อใหม่ให้กับฟังก์ชันรุ่นที่ 2 และค่อยๆ ย้ายการรับส่งข้อมูลไปยังฟังก์ชันดังกล่าว
คุณไม่สามารถอัปเกรดฟังก์ชันจากรุ่นที่ 1 เป็นรุ่นที่ 2 ด้วยชื่อเดียวกันและเรียกใช้ firebase deploy การดำเนินการดังกล่าวจะทำให้เกิดข้อผิดพลาดต่อไปนี้
Upgrading from GCFv1 to GCFv2 is not yet supported. Please delete your old function or wait for this feature to be ready.
ก่อนทำตามขั้นตอนเหล่านี้ โปรดตรวจสอบก่อนว่าฟังก์ชันของคุณเป็น Idempotent เนื่องจากทั้งฟังก์ชันเวอร์ชันใหม่และเวอร์ชันเก่าจะทำงานพร้อมกันระหว่างการเปลี่ยนแปลง ตัวอย่างเช่น หากคุณมีฟังก์ชันรุ่นที่ 1 ที่ตอบสนองต่อเหตุการณ์การเขียนใน Firestore ให้ตรวจสอบว่าการตอบสนองต่อการเขียน 2 ครั้ง ครั้งหนึ่งโดยฟังก์ชันรุ่นที่ 1 และอีกครั้งโดยฟังก์ชันรุ่นที่ 2 เพื่อตอบสนองต่อเหตุการณ์เหล่านั้นจะทำให้แอปอยู่ในสถานะที่สอดคล้องกัน
- เปลี่ยนชื่อฟังก์ชันในโค้ดฟังก์ชัน เช่น เปลี่ยนชื่อ
resizeImageเป็นresizeImageSecondGen - ทำให้ฟังก์ชันใช้งานได้เพื่อให้ทั้งฟังก์ชันรุ่นที่ 1 เดิมและฟังก์ชันรุ่นที่ 2 ทำงาน
- ในกรณีของทริกเกอร์ที่เรียกใช้ได้, ทริกเกอร์ Task Queue และทริกเกอร์ HTTP ให้เริ่มชี้ไคลเอ็นต์ทั้งหมดไปยังฟังก์ชันรุ่นที่ 2 โดยการอัปเดตโค้ดไคลเอ็นต์ด้วยชื่อหรือ URL ของฟังก์ชันรุ่นที่ 2
- สำหรับทริกเกอร์เบื้องหลัง ทั้งฟังก์ชันรุ่นที่ 1 และรุ่นที่ 2 จะตอบสนองต่อทุกเหตุการณ์ทันทีเมื่อทำให้ใช้งานได้
- เมื่อย้ายการรับส่งข้อมูลทั้งหมดออกแล้ว ให้ลบฟังก์ชันรุ่นที่ 1 โดยใช้คำสั่ง
firebase functions:deleteของ Firebase CLI- คุณจะเปลี่ยนชื่อฟังก์ชันรุ่นที่ 2 ให้ตรงกับชื่อของฟังก์ชันรุ่นที่ 1 ก็ได้ (ไม่บังคับ)