Quản lý các hàm (thế hệ thứ nhất)

Bạn có thể triển khai, xoá và sửa đổi hàm bằng cách sử dụng các lệnh CLI Firebase hoặc bằng cách thiết lập các tuỳ chọn thời gian chạy trong mã nguồn hàm.

Triển khai hàm

Để triển khai hàm, hãy chạy lệnh Firebase CLI sau:

firebase deploy --only functions

Theo mặc định, Firebase CLI sẽ triển khai tất cả các hàm bên trong nguồn của bạn cùng một lúc. Nếu dự án của bạn chứa hơn 5 hàm, bạn nên sử dụng cờ --only với tên hàm cụ thể để chỉ triển khai các hàm mà bạn đã chỉnh sửa. Việc triển khai các hàm cụ thể theo cách này sẽ giúp tăng tốc quá trình triển khai và giúp bạn tránh gặp phải hạn mức triển khai. Ví dụ:

firebase deploy --only functions:addMessage,functions:makeUppercase

Khi triển khai số lượng lớn hàm, bạn có thể vượt quá hạn mức tiêu chuẩn và nhận được thông báo lỗi HTTP 429 hoặc 500. Để giải quyết vấn đề này, hãy triển khai các hàm theo nhóm 10 hàm trở xuống.

Hãy xem tài liệu tham khảo về Firebase CLI để biết danh sách đầy đủ các lệnh có sẵn.

Theo mặc định, Firebase CLI sẽ tìm mã nguồn trong thư mục functions/ cho mã nguồn. Nếu muốn, bạn có thể sắp xếp các hàm trong cơ sở mã hoặc nhiều nhóm tệp.

Xoá hàm

Bạn có thể xoá các hàm đã triển khai trước đó theo những cách sau:

  • rõ ràng trong Firebase CLI bằng functions:delete
  • rõ ràng trong Google Cloud bảng điều khiển.
  • ngầm bằng cách xoá hàm khỏi nguồn trước khi triển khai.

Tất cả các thao tác xoá đều yêu cầu bạn xác nhận trước khi xoá hàm khỏi môi trường thực tế.

Thao tác xoá hàm rõ ràng trong Firebase CLI hỗ trợ nhiều đối số cũng như các nhóm hàm và cho phép bạn chỉ định một hàm đang chạy ở một khu vực cụ thể. Ngoài ra, bạn có thể ghi đè lời nhắc xác nhận.

  • Xoá tất cả các hàm khớp với tên đã chỉ định ở tất cả các khu vực:

    firebase functions:delete FUNCTION-1_NAME

  • Xoá một hàm đã chỉ định đang chạy ở một khu vực không phải khu vực mặc định:

    firebase functions:delete FUNCTION-1_NAME --region REGION_NAME

  • Xoá nhiều hàm:

    firebase functions:delete FUNCTION-1_NAME FUNCTION-2_NAME

  • Xoá một nhóm hàm đã chỉ định:

    firebase functions:delete GROUP_NAME

  • Bỏ qua lời nhắc xác nhận:

    firebase functions:delete FUNCTION-1_NAME --force

Với thao tác xoá hàm ngầm, firebase deploy sẽ phân tích nguồn của bạn và xoá mọi hàm đã bị xoá khỏi tệp khỏi môi trường thực tế.

Sửa đổi tên, khu vực hoặc trình kích hoạt của hàm

Nếu bạn đang đổi tên hoặc thay đổi vùng hoặc điều kiện kích hoạt cho các hàm đang xử lý lưu lượng truy cập phát hành công khai, hãy làm theo các bước trong phần này để tránh mất sự kiện trong quá trình sửa đổi. Trước khi làm theo các bước này, trước tiên, hãy đảm bảo rằng hàm của bạn là hàm luỹ đẳng, vì cả phiên bản mới và phiên bản cũ của hàm sẽ chạy cùng một lúc trong quá trình thay đổi.

Đổi tên hàm

Để đổi tên hàm, hãy tạo một phiên bản mới đã đổi tên của hàm trong nguồn của bạn, sau đó chạy hai lệnh triển khai riêng biệt. Lệnh đầu tiên triển khai hàm được đặt tên mới và lệnh thứ hai xoá phiên bản đã triển khai trước đó. Ví dụ: nếu bạn có một hàm Node.js có tên là webhook mà bạn muốn đổi thành webhookNew, hãy sửa đổi mã như sau:

// before
const functions = require('firebase-functions/v1');

exports.webhook = functions.https.onRequest((req, res) => {
    res.send("Hello");
});

// after
const functions = require('firebase-functions/v1');

exports.webhookNew = functions.https.onRequest((req, res) => {
    res.send("Hello");
});

Sau đó, hãy chạy các lệnh sau để triển khai hàm mới:

# Deploy new function called webhookNew
firebase deploy --only functions:webhookNew

# Wait until deployment is done; now both webhookNew and webhook are running

# Delete webhook
firebase functions:delete webhook

Thay đổi khu vực hoặc các khu vực của hàm

Nếu bạn đang thay đổi các khu vực đã chỉ định cho một hàm đang xử lý lưu lượng truy cập thực tế, bạn có thể ngăn chặn tình trạng mất sự kiện bằng cách thực hiện các bước sau theo thứ tự:

  1. Đổi tên hàm và thay đổi khu vực hoặc các khu vực của hàm theo ý muốn.
  2. Triển khai hàm đã đổi tên. Thao tác này sẽ tạm thời chạy cùng một mã trong cả hai nhóm khu vực.
  3. Xoá hàm trước đó.

Ví dụ: nếu bạn có một hàm có tên là webhook hiện đang ở khu vực hàm mặc định là us-central1 và bạn muốn di chuyển hàm đó sang asia-northeast1, thì trước tiên, bạn cần sửa đổi mã nguồn để đổi tên hàm và sửa đổi khu vực.

// before
const functions = require('firebase-functions/v1');

exports.webhook = functions
    .https.onRequest((req, res) => {
            res.send("Hello");
    });

// after
const functions = require('firebase-functions/v1');

exports.webhookAsia = functions
    .region('asia-northeast1')
    .https.onRequest((req, res) => {
            res.send("Hello");
    });

Sau đó, hãy triển khai bằng cách chạy:

firebase deploy --only functions:webhookAsia

Hiện có hai hàm giống hệt nhau đang chạy: webhook đang chạy ở us-central1, và webhookAsia đang chạy ở asia-northeast1.

Sau đó, hãy xoá webhook:

firebase functions:delete webhook

Hiện chỉ có một hàm là webhookAsia đang chạy ở asia-northeast1.

Thay đổi loại trình kích hoạt của hàm

Khi bạn phát triển quá trình triển khai Cloud Functions for Firebase theo thời gian, bạn có thể cần thay đổi loại điều kiện kích hoạt của hàm vì nhiều lý do. Ví dụ: bạn có thể muốn thay đổi từ một loại sự kiện Firebase Realtime Database hoặc Cloud Firestore sang một loại khác.

Bạn không thể thay đổi loại sự kiện của hàm chỉ bằng cách thay đổi mã nguồn và chạy firebase deploy. Để tránh lỗi, hãy thay đổi loại trình kích hoạt của hàm theo quy trình sau:

  1. Sửa đổi mã nguồn để thêm một hàm mới có loại trình kích hoạt mong muốn.
  2. Triển khai hàm. Thao tác này sẽ tạm thời chạy cả hàm cũ và hàm mới.
  3. Xoá rõ ràng hàm cũ khỏi môi trường thực tế bằng Firebase CLI.

Ví dụ: nếu bạn có một hàm Node.js có tên là objectChanged có loại sự kiện onChange cũ và bạn muốn thay đổi thành onFinalize, trước tiên, hãy đổi tên hàm và chỉnh sửa để có loại sự kiện onFinalize.

// before
const functions = require('firebase-functions/v1');

exports.objectChanged = functions.storage.object().onChange((object) => {
    return console.log('File name is: ', object.name);
});

// after
const functions = require('firebase-functions/v1');

exports.objectFinalized = functions.storage.object().onFinalize((object) => {
    return console.log('File name is: ', object.name);
});

Sau đó, hãy chạy các lệnh sau để tạo hàm mới trước khi xoá hàm cũ:

# Create new function objectFinalized
firebase deploy --only functions:objectFinalized

# Wait until deployment is done; now both objectChanged and objectFinalized are running

# Delete objectChanged
firebase functions:delete objectChanged

Thiết lập các tuỳ chọn thời gian chạy

Cloud Functions for Firebase cho phép bạn chọn các tuỳ chọn thời gian chạy, chẳng hạn như phiên bản thời gian chạy Node.js và thời gian chờ cho mỗi hàm, việc phân bổ bộ nhớ và số thực thể hàm tối thiểu/tối đa.

Theo phương pháp hay nhất, bạn nên thiết lập các tuỳ chọn này (ngoại trừ phiên bản Node.js) trên một đối tượng cấu hình bên trong mã hàm. Đối tượng RuntimeOptions này là nguồn thông tin chính xác cho các tuỳ chọn thời gian chạy của hàm và sẽ ghi đè các tuỳ chọn được thiết lập bằng bất kỳ phương thức nào khác (chẳng hạn như Google Cloud hoặc gcloud CLI).

Nếu quy trình phát triển của bạn liên quan đến việc thiết lập các tuỳ chọn thời gian chạy theo cách thủ công bằng Google Cloud bảng điều khiển hoặc gcloud CLI và bạn không muốn các giá trị này bị ghi đè trên mỗi lần triển khai, hãy đặt tuỳ chọn preserveExternalChanges thành true. Khi tuỳ chọn này được đặt thành true, Firebase sẽ hợp nhất các tuỳ chọn thời gian chạy được thiết lập trong mã của bạn với chế độ cài đặt của phiên bản hàm hiện được triển khai theo mức độ ưu tiên sau:

  1. Tuỳ chọn được thiết lập trong mã hàm: ghi đè các thay đổi bên ngoài.
  2. Tuỳ chọn được thiết lập thành RESET_VALUE trong mã hàm: ghi đè các thay đổi bên ngoài bằng giá trị mặc định.
  3. Tuỳ chọn không được thiết lập trong mã hàm, nhưng được thiết lập trong hàm hiện được triển khai: sử dụng tuỳ chọn được chỉ định trong hàm đã triển khai.

Bạn không nên sử dụng tuỳ chọn preserveExternalChanges: true cho hầu hết các trường hợp vì mã của bạn sẽ không còn là nguồn thông tin chính xác đầy đủ cho các tuỳ chọn thời gian chạy của hàm nữa. Nếu bạn sử dụng tuỳ chọn này, hãy kiểm tra bảng điều khiển Google Cloud hoặc sử dụng gcloud CLI để xem cấu hình đầy đủ của hàm.

Thiết lập phiên bản Node.js

Firebase SDK cho Cloud Functions cho phép chọn thời gian chạy Node.js. Bạn có thể chọn chạy tất cả các hàm trong một dự án chỉ trên môi trường thời gian chạy tương ứng với một trong các phiên bản Node.js được hỗ trợ sau:

  • Node.js 22
  • Node.js 20
  • Node.js 18 (không dùng nữa)

Hãy xem lịch hỗ trợ để biết thông tin quan trọng về việc hỗ trợ liên tục cho các phiên bản Node.js này.

Cách thiết lập phiên bản Node.js:

Bạn có thể thiết lập phiên bản trong trường engines trong tệp package.json được tạo trong thư mục functions/ trong quá trình khởi chạy. Ví dụ: để chỉ sử dụng phiên bản 20, hãy chỉnh sửa dòng này trong package.json:

  "engines": {"node": "22"}

Nếu bạn đang sử dụng trình quản lý gói Yarn hoặc có các yêu cầu cụ thể khác cho trường engines, bạn có thể thiết lập thời gian chạy cho Firebase SDK cho Cloud Functions trong firebase.json thay vì:

  {
    "functions": {
      "runtime": "nodejs22"
    }
  }

CLI sẽ ưu tiên sử dụng giá trị được thiết lập trong firebase.json hơn bất kỳ giá trị hoặc phạm vi nào mà bạn thiết lập riêng trong package.json.

Nâng cấp thời gian chạy Node.js

Cách nâng cấp thời gian chạy Node.js:

  1. Đảm bảo dự án của bạn đang sử dụng gói giá Blaze.
  2. Đảm bảo bạn đang sử dụng Firebase CLI phiên bản 11.18.0 trở lên.
  3. Thay đổi giá trị engines trong tệp package.json được tạo trong thư mục functions/ trong quá trình khởi chạy. Ví dụ: nếu bạn đang nâng cấp từ phiên bản 16 lên phiên bản 18, thì mục nhập sẽ có dạng như sau: "engines": {"node": "18"}
  4. Bạn có thể kiểm thử các thay đổi bằng cách sử dụng Firebase Local Emulator Suite.
  5. Triển khai lại tất cả các hàm.

Chọn hệ thống mô-đun Node.js

Hệ thống mô-đun mặc định trong Node.js là CommonJS (CJS), nhưng các phiên bản Node.js hiện tại cũng hỗ trợ Mô-đun ECMAScript (ESM). Cloud Functions hỗ trợ cả hai.

Theo mặc định, các hàm của bạn sử dụng CommonJS. Điều đó có nghĩa là các lệnh nhập và xuất sẽ có dạng như sau:

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

exports.helloWorld = functions.https.onRequest(async (req, res) => res.send("Hello from Firebase!"));

Để sử dụng ESM, hãy thiết lập trường "type": "module" trong tệp package.json file :

  {
   ...
   "type": "module",
   ...
  }

Sau khi bạn thiết lập trường này, hãy sử dụng cú pháp importexport của ESM:

import functions from "firebase-functions/v1";

export const helloWorld = functions.https.onRequest(async (req, res) => res.send("Hello from Firebase!"));

Cả hai hệ thống mô-đun đều được hỗ trợ đầy đủ. Bạn có thể chọn hệ thống phù hợp nhất với dự án của mình. Tìm hiểu thêm trong tài liệu về mô-đun của Node.js.

Kiểm soát hành vi mở rộng quy mô

Theo mặc định, Cloud Functions for Firebase sẽ mở rộng quy mô số lượng thực thể đang chạy dựa trên số lượng yêu cầu đến, có thể giảm xuống còn 0 thực thể trong thời gian lưu lượng truy cập giảm. Tuy nhiên, nếu ứng dụng của bạn yêu cầu giảm độ trễ và bạn muốn giới hạn số lần khởi động nguội, bạn có thể thay đổi hành vi mặc định này bằng cách chỉ định số lượng thực thể vùng chứa tối thiểu cần được duy trì ở trạng thái sẵn sàng để xử lý các yêu cầu.

Tương tự, bạn có thể thiết lập số lượng tối đa để giới hạn việc mở rộng quy mô các thực thể nhằm phản hồi các yêu cầu đến. Hãy sử dụng chế độ cài đặt này để kiểm soát chi phí hoặc giới hạn số lượng kết nối với dịch vụ hỗ trợ, chẳng hạn như với cơ sở dữ liệu.

Giảm số lần khởi động nguội

Để thiết lập số lượng thực thể tối thiểu cho một hàm trong mã nguồn, hãy sử dụng phương thức runWith. Phương thức này chấp nhận một đối tượng JSON tuân thủ RuntimeOptions giao diện, xác định giá trị cho minInstances. Ví dụ: hàm này thiết lập tối thiểu 5 thực thể để duy trì ở trạng thái sẵn sàng:

exports.getAutocompleteResponse = functions
    .runWith({
      // Keep 5 instances warm for this latency-critical function
      minInstances: 5,
    })
    .https.onCall((data, context) => {
      // Autocomplete a user's search term
    });

Dưới đây là một số điều cần cân nhắc khi thiết lập giá trị cho minInstances:

  • Nếu Cloud Functions for Firebase mở rộng quy mô ứng dụng của bạn vượt quá chế độ cài đặt minInstances, bạn sẽ gặp phải tình trạng khởi động nguội cho mỗi thực thể vượt quá ngưỡng đó.
  • Tình trạng khởi động nguội có ảnh hưởng nghiêm trọng nhất đến các ứng dụng có lưu lượng truy cập tăng đột biến. Nếu ứng dụng của bạn có lưu lượng truy cập tăng đột biến và bạn thiết lập giá trị minInstances đủ cao để giảm tình trạng khởi động nguội khi lưu lượng truy cập tăng, bạn sẽ thấy độ trễ giảm đáng kể. Đối với các ứng dụng có lưu lượng truy cập không đổi, tình trạng khởi động nguội không có khả năng ảnh hưởng nghiêm trọng đến hiệu suất.
  • Việc thiết lập số thực thể tối thiểu có thể hữu ích cho môi trường thực tế, nhưng thường nên tránh trong môi trường thử nghiệm. Để giảm xuống còn 0 trong dự án thử nghiệm nhưng vẫn giảm tình trạng khởi động nguội trong dự án thực tế, bạn có thể thiết lập minInstances dựa trên biến môi trường FIREBASE_CONFIG:

    // Get Firebase project id from `FIREBASE_CONFIG` environment variable
    const envProjectId = JSON.parse(process.env.FIREBASE_CONFIG).projectId;
    
    exports.renderProfilePage = functions
        .runWith({
          // Keep 5 instances warm for this latency-critical function
          // in production only. Default to 0 for test projects.
          minInstances: envProjectId === "my-production-project" ? 5 : 0,
        })
        .https.onRequest((req, res) => {
          // render some html
        });
    

Giới hạn số lượng thực thể tối đa cho một hàm

Để thiết lập số thực thể tối đa trong mã nguồn hàm, hãy sử dụng runWith phương thức. Phương thức này chấp nhận một đối tượng JSON tuân thủ RuntimeOptions giao diện, xác định các giá trị cho maxInstances. Ví dụ: hàm này thiết lập giới hạn 100 thực thể để không làm quá tải cơ sở dữ liệu cũ giả định:

exports.mirrorOrdersToLegacyDatabase = functions
    .runWith({
      // Legacy database only supports 100 simultaneous connections
      maxInstances: 100,
    })
    .firestore.document("orders/{orderId}")
    .onWrite((change, context) => {
      // Connect to legacy database
    });

Nếu một hàm HTTP được mở rộng quy mô lên đến giới hạn maxInstances, các yêu cầu mới sẽ được xếp hàng đợi trong 30 giây rồi bị từ chối với mã phản hồi 429 Too Many Requests nếu không có thực thể nào vào thời điểm đó.

Để tìm hiểu thêm về các phương pháp hay nhất để sử dụng chế độ cài đặt số thực thể tối đa, hãy xem các phương pháp hay nhất này để sử dụng maxInstances.

Thiết lập tài khoản dịch vụ

Tài khoản dịch vụ mặc định cho các hàm thế hệ thứ 1, PROJECT_ID@appspot.gserviceaccount.com (có tên là Tài khoản dịch vụ mặc định của App Engine), có một tập hợp quyền rộng rãi để cho phép bạn tương tác với các dịch vụ khác của Firebase và Google Cloud.

Bạn có thể muốn ghi đè tài khoản dịch vụ mặc định và giới hạn một hàm ở các tài nguyên chính xác cần thiết. Bạn có thể thực hiện việc này bằng cách tạo một tài khoản dịch vụ tuỳ chỉnh và chỉ định tài khoản đó cho hàm thích hợp bằng phương thức .runWith(). Phương thức này lấy một đối tượng có các tuỳ chọn cấu hình, bao gồm cả thuộc tính serviceAccount.

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

exports.helloWorld = functions
    .runWith({
        // This function doesn't access other Firebase project resources, so it uses a limited service account.
        serviceAccount:
            "my-limited-access-sa@", // or prefer the full form: "my-limited-access-sa@my-project.iam.gserviceaccount.com"
    })
    .https.onRequest((request, response) => {
        response.send("Hello from Firebase!");
    });

Thiết lập thời gian chờ và việc phân bổ bộ nhớ

Trong một số trường hợp, các hàm của bạn có thể có các yêu cầu đặc biệt về giá trị thời gian chờ dài hoặc việc phân bổ bộ nhớ lớn. Bạn có thể thiết lập các giá trị này trong Bảng điều khiển Google Cloud hoặc trong mã nguồn hàm (chỉ Firebase).

Để thiết lập việc phân bổ bộ nhớ và thời gian chờ trong mã nguồn hàm, hãy sử dụng tham số runWith được giới thiệu trong Firebase SDK cho Cloud Functions 2.0.0. Tuỳ chọn thời gian chạy này chấp nhận một đối tượng JSON tuân thủ RuntimeOptions giao diện, xác định các giá trị cho timeoutSecondsmemory. Ví dụ: hàm lưu trữ này sử dụng 1 GB bộ nhớ và hết thời gian chờ sau 300 giây:

exports.convertLargeFile = functions
    .runWith({
      // Ensure the function has enough memory and time
      // to process large files
      timeoutSeconds: 300,
      memory: "1GB",
    })
    .storage.object()
    .onFinalize((object) => {
      // Do some complicated things that take a lot of memory and time
    });

Giá trị tối đa cho timeoutSeconds540 hoặc 9 phút. Dung lượng bộ nhớ được cấp cho một hàm tương ứng với CPU được phân bổ cho hàm đó, như được nêu chi tiết trong danh sách các giá trị hợp lệ cho memory:

  • 128MB – 200 MHz
  • 256MB – 400 MHz
  • 512MB – 800 MHz
  • 1GB – 1,4 GHz
  • 2GB – 2,4 GHz
  • 4GB – 4,8 GHz
  • 8GB – 4,8 GHz

Cách thiết lập việc phân bổ bộ nhớ và thời gian chờ trong bảng điều khiển Google Cloud:

  1. Trong bảng điều khiển Google Cloud, hãy chọn Cloud Functions trong trình đơn bên trái.
  2. Chọn một hàm bằng cách nhấp vào tên của hàm đó trong danh sách hàm.
  3. Nhấp vào biểu tượng Chỉnh sửa trong trình đơn trên cùng.
  4. Chọn một mức phân bổ bộ nhớ trong trình đơn thả xuống có nhãn Memory allocated (Bộ nhớ được phân bổ).
  5. Nhấp vào More (Thêm) để hiển thị các tuỳ chọn nâng cao và nhập số giây vào hộp văn bản Timeout (Thời gian chờ).
  6. Nhấp vào Save (Lưu) để cập nhật hàm.