อัปเกรดฟังก์ชัน Node.js รุ่นที่ 1 เป็นรุ่นที่ 2

แอปที่ใช้ฟังก์ชันรุ่นที่ 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 ใน firebase-functions SDK เส้นทางการนำเข้าที่แตกต่างกันนี้คือ Firebase CLI ทั้งหมดที่จำเป็นในการพิจารณาว่าจะปรับใช้โค้ดฟังก์ชันของคุณเป็นฟังก์ชันรุ่นที่ 1 หรือ 2

แพ็คเกจย่อย v2 เป็นแบบโมดูลาร์ และเราขอแนะนำให้นำเข้าเฉพาะโมดูลเฉพาะที่คุณต้องการเท่านั้น

ก่อน: รุ่นที่ 1

const functions = require("firebase-functions");

หลัง: รุ่นที่ 2

// explicitly import each trigger
const {onRequest} = require("firebase-functions/v2/https");
const {onDocumentCreated} = require("firebase-functions/v2/firestore");

อัปเดตคำจำกัดความของทริกเกอร์

เนื่องจาก SDK รุ่นที่ 2 สนับสนุนการนำเข้าแบบโมดูลาร์ ให้อัปเดตข้อกำหนดทริกเกอร์เพื่อให้สะท้อนถึงการนำเข้าที่เปลี่ยนแปลงจากขั้นตอนก่อนหน้า

อาร์กิวเมนต์ที่ส่งไปยังการเรียกกลับสำหรับทริกเกอร์บางตัวมีการเปลี่ยนแปลง ในตัวอย่างนี้ โปรดทราบว่าอาร์กิวเมนต์ของการโทรกลับ onDocumentCreated ได้ถูกรวมเข้าไว้ในอ event เดียว นอกจากนี้ ทริกเกอร์บางตัวยังมีฟีเจอร์การกำหนดค่าใหม่ที่สะดวกสบาย เช่น ตัวเลือก cors ของทริกเกอร์ onRequest

ก่อน: รุ่นที่ 1

const functions = require("firebase-functions");

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 จะบล็อกการปรับใช้ เว้นแต่ว่าพารามิเตอร์ทั้งหมดจะมีค่าที่ถูกต้อง เพื่อให้แน่ใจว่าฟังก์ชันจะไม่ถูกปรับใช้โดยไม่มีการกำหนดค่าที่ขาดหายไป

ย้ายไปยังแพ็คเกจย่อย params

หากคุณใช้การกำหนดค่าสภาพแวดล้อมด้วย functions.config คุณสามารถย้ายการกำหนดค่าที่มีอยู่ไปเป็นการ กำหนดค่าแบบกำหนดพารามิเตอร์ได้

ก่อน: รุ่นที่ 1

const functions = require("firebase-functions");

exports.date = functions.https.onRequest((req, res) => {
  const date = new Date();
  const formattedDate =
date.toLocaleDateString(functions.config().dateformat);

  // ...
});

หลัง: รุ่นที่ 2

const {onRequest} = require("firebase-functions/v2/https");
const {defineString} = require("firebase-functions/params");

const dateFormat = defineString("DATE_FORMAT");

exports.date = onRequest((req, res) => {
  const date = new Date();
  const formattedDate = date.toLocaleDateString(dateFormat.value());

  // ...
});

ตั้งค่าพารามิเตอร์

ครั้งแรกที่คุณปรับใช้ Firebase CLI จะแจ้งค่าพารามิเตอร์ทั้งหมด และบันทึกค่าในไฟล์ dotenv หากต้องการส่งออกค่าของ function.config ให้เรียกใช้ firebase functions:config:export

เพื่อความปลอดภัยเพิ่มเติม คุณยังสามารถระบุ ประเภท พารามิเตอร์และ กฎการตรวจสอบได้

กรณีพิเศษ: คีย์ API

โมดูล params ผสานรวมกับ Cloud Secret Manager ซึ่งให้การควบคุมการเข้าถึงค่าที่ละเอียดอ่อนเช่นคีย์ API แบบละเอียด ดู พารามิเตอร์ลับ สำหรับข้อมูลเพิ่มเติม

ก่อน: รุ่นที่ 1

const functions = require("firebase-functions");

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());
    // ...
  }
);

ตั้งค่าตัวเลือกรันไทม์

การกำหนด ค่าตัวเลือกรันไทม์ มีการเปลี่ยนแปลงระหว่างรุ่นที่ 1 และรุ่นที่ 2 รุ่นที่ 2 ยังเพิ่มความสามารถใหม่ในการตั้งค่าตัวเลือกสำหรับฟังก์ชั่นทั้งหมด

ก่อน: รุ่นที่ 1

const functions = require("firebase-functions");

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) => {
  /* ... */
});

ใช้พร้อมกัน

ข้อได้เปรียบที่สำคัญของฟังก์ชันรุ่นที่ 2 คือความสามารถของอินสแตนซ์ฟังก์ชันเดียวในการให้บริการมากกว่าหนึ่งคำขอในคราวเดียว สิ่งนี้สามารถลดจำนวนการสตาร์ทขณะเย็นที่ผู้ใช้ปลายทางประสบได้อย่างมาก ตามค่าเริ่มต้น การทำงานพร้อมกันจะถูกตั้งค่าไว้ที่ 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 ตรวจสอบให้แน่ใจว่าการตอบสนองต่อการเขียนสองครั้ง ครั้งหนึ่งโดยฟังก์ชันรุ่นที่ 1 และอีกครั้งหนึ่งโดยฟังก์ชันรุ่นที่ 2 เพื่อตอบสนองต่อเหตุการณ์เหล่านั้นจะทำให้แอปของคุณอยู่ใน สถานะที่สอดคล้องกัน

  1. เปลี่ยนชื่อฟังก์ชันในโค้ดฟังก์ชันของคุณ ตัวอย่างเช่น เปลี่ยนชื่อ resizeImage เป็น resizeImageSecondGen
  2. ปรับใช้ฟังก์ชัน เพื่อให้ทั้งฟังก์ชันรุ่นที่ 1 ดั้งเดิมและฟังก์ชันรุ่นที่ 2 ทำงานอยู่
    1. ในกรณีของทริกเกอร์ที่เรียกได้ คิวงาน และ HTTP ให้เริ่มชี้ไคลเอ็นต์ทั้งหมดไปยังฟังก์ชันเจนเนอเรชัน 2 โดยการอัปเดตโค้ดไคลเอ็นต์ด้วยชื่อหรือ URL ของฟังก์ชันเจนเนอเรชั่น 2
    2. ด้วยทริกเกอร์เบื้องหลัง ทั้งฟังก์ชันรุ่นที่ 1 และรุ่นที่ 2 จะตอบสนองต่อทุกเหตุการณ์ทันทีเมื่อปรับใช้
  3. เมื่อการรับส่งข้อมูลทั้งหมดถูกย้ายออก ให้ลบฟังก์ชันรุ่นที่ 1 โดยใช้คำสั่ง firebase functions:delete ของ firebase CLI
    1. หรือเปลี่ยนชื่อฟังก์ชันรุ่นที่ 2 ให้ตรงกับชื่อของฟังก์ชันรุ่นที่ 1