ניהול פונקציות (דור ראשון)

אפשר לפרוס, למחוק ולשנות פונקציות באמצעות פקודות CLI של Firebase או על ידי הגדרת אפשרויות זמן ריצה בקוד המקור של הפונקציות.

פריסת פונקציות

כדי לפרוס פונקציות, מריצים את פקודת ה-CLI הבאה של Firebase:

firebase deploy --only functions

כברירת מחדל, ה-CLI של Firebase פורס את כל הפונקציות במקור בו-זמנית. אם הפרויקט מכיל יותר מ-5 פונקציות, מומלץ להשתמש בדגל --only עם שמות של פונקציות ספציפיות כדי לפרוס רק את הפונקציות שערכתם. פריסת פונקציות ספציפיות בדרך הזו מאיצה את תהליך הפריסה ועוזרת לכם להימנע מחריגה ממכסות הפריסה. לדוגמה:

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

כשפורסים מספר גדול של פונקציות, יכול להיות שתחרגו מהמכסה הרגילה ותקבלו הודעות שגיאה מסוג HTTP 429 או 500. כדי לפתור את הבעיה, צריך לפרוס פונקציות בקבוצות של 10 או פחות.

רשימה מלאה של הפקודות הזמינות מופיעה במאמרי העזרה של ה-CLI של Firebase.

כברירת מחדל, ה-CLI של Firebase מחפש את קוד המקור בתיקייה functions/. אם אתם מעדיפים, אתם יכולים לארגן פונקציות בבסיסי קוד או בכמה קבוצות של קבצים.

מחיקת פונקציות

אפשר למחוק פונקציות שנפרסו בעבר בדרכים הבאות:

  • באופן מפורש ב-CLI של Firebase באמצעות functions:delete
  • באופן מפורש במסוף Google Cloud.
  • באופן משתמע, על ידי הסרת הפונקציה מהמקור לפני הפריסה.

בכל פעולות המחיקה תתבקשו לאשר את הסרת הפונקציה מסביבת הייצור.

מחיקה מפורשת של פונקציות ב-CLI של Firebase תומכת בכמה ארגומנטים וגם בקבוצות של פונקציות, ומאפשרת לציין פונקציה שפועלת באזור מסוים. אפשר גם לבטל את הודעת האישור.

  • מוחק את כל הפונקציות שתואמות לשם שצוין בכל האזורים:

    firebase functions:delete FUNCTION-1_NAME

  • מחיקת פונקציה ספציפית שפועלת באזור שאינו ברירת המחדל:

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

  • מחיקה של יותר מפונקציה אחת:

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

  • מחיקה של קבוצת פונקציות מסוימת:

    firebase functions:delete GROUP_NAME

  • עוקף את בקשת האישור:

    firebase functions:delete FUNCTION-1_NAME --force

במחיקה משתמעת של פונקציות, firebase deploy מנתח את המקור ומסיר מהייצור את כל הפונקציות שהוסרו מהקובץ.

שינוי השם, האזור או הטריגר של פונקציה

אם אתם משנים את השם, האזורים או הטריגר של פונקציות שמטפלות בתנועה בסביבת הייצור, בצעו את השלבים שבקטע הזה כדי למנוע אובדן של אירועים במהלך השינוי. לפני שמבצעים את השלבים הבאים, צריך לוודא שהפונקציה היא אידמפוטנטית, כי גם הגרסה החדשה וגם הגרסה הישנה של הפונקציה יפעלו בו-זמנית במהלך השינוי.

שינוי שם של פונקציה

כדי לשנות את השם של פונקציה, צריך ליצור גרסה חדשה של הפונקציה עם השם החדש במקור, ואז להריץ שתי פקודות פריסה נפרדות. הפקודה הראשונה פורסת את הפונקציה בעלת השם החדש, והפקודה השנייה מסירה את הגרסה שנפרסה קודם. לדוגמה, אם יש לכם פונקציית Node.js בשם webhook ואתם רוצים לשנות אותה ל-webhookNew, צריך לשנות את הקוד באופן הבא:

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

לאחר מכן מריצים את הפקודות הבאות כדי לפרוס את הפונקציה החדשה:

# 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

שינוי האזור או האזורים של פונקציה

אם אתם משנים את האזורים שצוינו לפונקציה שמטפלת בתנועה בסביבת הייצור, כדי למנוע אובדן אירועים, בצעו את השלבים הבאים לפי הסדר:

  1. משנים את שם הפונקציה ואת האזור או האזורים שלה לפי הצורך.
  2. פורסים את הפונקציה עם השם החדש, וכך מריצים באופן זמני את אותו קוד בשתי קבוצות האזורים.
  3. מחיקת הפונקציה הקודמת.

לדוגמה, אם יש לכם פונקציה בשם webhook שפרוסה כרגע ב-us-central1, ואתם רוצים להעביר אותה ל-asia-northeast1, קודם צריך לשנות את קוד המקור כדי לשנות את שם הפונקציה ואת האזור.

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

ואז פורסים באמצעות הפקודה:

firebase deploy --only functions:webhookAsia

עכשיו פועלות שתי פונקציות זהות: webhook פועלת ב-us-central1, ו-webhookAsia פועלת ב-asia-northeast1.

אחר כך מוחקים את webhook:

firebase functions:delete webhook

עכשיו יש רק פונקציה אחת – webhookAsia, שפועלת ב-asia-northeast1.

שינוי סוג הטריגר של פונקציה

במהלך הפיתוח של פריסת Cloud Functions for Firebase, יכול להיות שתצטרכו לשנות את סוג הטריגר של פונקציה מסיבות שונות. לדוגמה, יכול להיות שתרצו לשנות את הסוג של אירוע Firebase Realtime Database או Cloud Firestore.

אי אפשר לשנות את סוג האירוע של פונקציה רק על ידי שינוי קוד המקור והרצת firebase deploy. כדי למנוע שגיאות, משנים את סוג הטריגר של הפונקציה לפי התהליך הבא:

  1. משנים את קוד המקור כך שיכלול פונקציה חדשה עם סוג הטריגר הרצוי.
  2. פורסים את הפונקציה, וכתוצאה מכך הפונקציות הישנות והחדשות פועלות באופן זמני.
  3. מוחקים באופן מפורש את הפונקציה הישנה מהסביבה בסביבת הייצור באמצעות ה-CLI של Firebase.

לדוגמה, אם יש לכם פונקציית Node.js בשם objectChanged עם סוג האירוע הקודם onChange, ואתם רוצים לשנות אותו ל-onFinalize, קודם צריך לשנות את שם הפונקציה ולערוך אותה כך שתכלול את סוג האירוע 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);
});

אחר כך מריצים את הפקודות הבאות כדי ליצור את הפונקציה החדשה לפני שמוחקים את הפונקציה הישנה:

# 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

הגדרת אפשרויות של סביבת זמן ריצה

Cloud Functions for Firebase מאפשר לבחור אפשרויות של סביבת זמן ריצה, כמו גרסת סביבת זמן הריצה של Node.js, זמן קצוב לתפוגה לכל פונקציה, הקצאת זיכרון ומספר מינימלי/מקסימלי של מכונות פונקציה.

השיטה המומלצת היא להגדיר את האפשרויות האלה (חוץ מהגרסה של Node.js) באובייקט הגדרה בתוך קוד הפונקציה. האובייקט RuntimeOptions הזה הוא מקור המידע המהימן לאפשרויות של סביבת זמן הריצה של הפונקציה, והוא יחליף את האפשרויות שהוגדרו בכל שיטה אחרת (כמו מסוף Google Cloud או gcloud CLI).

אם תהליך הפיתוח שלכם כולל הגדרה ידנית של אפשרויות זמן ריצה באמצעות מסוף Google Cloud או gcloud CLI, ואתם לא רוצים שהערכים האלה יוחלפו בכל פריסה, הגדירו את האפשרות preserveExternalChanges לערך true. כשהאפשרות הזו מוגדרת ל-true, Firebase ממזגת את אפשרויות זמן הריצה שהוגדרו בקוד עם ההגדרות של הגרסה הנוכחית של הפונקציה שנפרסה, לפי סדר העדיפויות הבא:

  1. האפשרות מוגדרת בקוד הפונקציות: ביטול שינויים חיצוניים.
  2. האפשרות מוגדרת ל-RESET_VALUE בקוד הפונקציות: שינויים חיצוניים יוחלפו בערך ברירת המחדל.
  3. האפשרות לא מוגדרת בקוד הפונקציות, אבל היא מוגדרת בפונקציה שנפרסה: משתמשים באפשרות שצוינה בפונקציה שנפרסה.

לא מומלץ להשתמש באפשרות preserveExternalChanges: true ברוב התרחישים, כי הקוד כבר לא יהיה מקור האמת המלא לאפשרויות זמן הריצה של הפונקציות. אם אתם משתמשים בו, בדקו את מסוף Google Cloud או השתמשו ב-gcloud CLI כדי לראות את ההגדרות המלאות של הפונקציה.

הגדרת הגרסה של Node.js

ערכת ה-SDK של Firebase ל-Cloud Functions מאפשרת לבחור סביבת זמן ריצה של Node.js. אתם יכולים להריץ את כל הפונקציות בפרויקט רק בסביבת זמן הריצה שתואמת לאחת מהגרסאות הנתמכות של Node.js:

  • Node.js 22
  • Node.js 20
  • ‫Node.js 18 (הוצא משימוש)

בלוח הזמנים של התמיכה מופיע מידע חשוב לגבי התמיכה השוטפת בגרסאות האלה של Node.js.

כדי להגדיר את הגרסה של Node.js:

אפשר להגדיר את הגרסה בשדה engines בקובץ package.json שנוצר בספרייה functions/ במהלך האתחול. לדוגמה, כדי להשתמש רק בגרסה 20, עורכים את השורה הזו ב-package.json:

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

אם אתם משתמשים במנהל החבילות Yarn או שיש לכם דרישות ספציפיות אחרות לשדה engines, אתם יכולים להגדיר את סביבת זמן הריצה של ה-SDK של Firebase ל-Cloud Functions ב-firebase.json במקום זאת:

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

ה-CLI משתמש בערך שמוגדר ב-firebase.json במקום בכל ערך או טווח שמוגדרים בנפרד ב-package.json.

שדרוג סביבת זמן הריצה של Node.js

כדי לשדרג את סביבת זמן הריצה של Node.js:

  1. מוודאים שהפרויקט מוגדר למינוי Blaze בתשלום לפי שימוש.
  2. חשוב לוודא שאתם משתמשים ב-Firebase CLI בגרסה 11.18.0 ואילך.
  3. משנים את הערך של engines בקובץ package.json שנוצר בספרייה functions/ במהלך האתחול. לדוגמה, אם משדרגים מגרסה 16 לגרסה 18, הרשומה צריכה להיראות כך: "engines": {"node": "18"}
  4. אפשר לבדוק את השינויים באמצעות Firebase Local Emulator Suite.
  5. פורסים מחדש את כל הפונקציות.

בחירת מערכת מודולים של Node.js

מערכת המודולים שמוגדרת כברירת מחדל ב-Node.js היא CommonJS‏ (CJS), אבל הגרסאות הנוכחיות של Node.js תומכות גם במודולים של ECMAScript‏ (ESM). ‫Cloud Functions תומך בשניהם.

כברירת מחדל, הפונקציות משתמשות ב-CommonJS. זה אומר שהייבוא והייצוא נראים כך:

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

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

כדי להשתמש ב-ESM במקום זאת, מגדירים את השדה "type": "module" בקובץ package.json:

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

אחרי שמגדירים את זה, משתמשים בתחביר ESM import ו-export:

import functions from "firebase-functions/v1";

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

שתי מערכות המודולים נתמכות באופן מלא. אתם יכולים לבחור את האפשרות שהכי מתאימה לפרויקט שלכם. מידע נוסף זמין במסמכי התיעוד של Node.js בנושא מודולים.

שליטה בהתנהגות של התאמה לעומס (auto-scaling)

כברירת מחדל, ב-Cloud Functions for Firebase מספר המכונות שפועלות משתנה בהתאם למספר הבקשות הנכנסות, ויכול להיות שהוא יצטמצם לאפס מכונות בזמנים שבהם יש פחות תנועה. עם זאת, אם האפליקציה דורשת זמן אחזור קצר יותר ואתם רוצים להגביל את מספר ההפעלות במצב התחלתי, אתם יכולים לשנות את התנהגות ברירת המחדל הזו על ידי ציון מספר מינימלי של מכונות קונטיינר שצריך לשמור במצב פעיל ומוכן להצגת בקשות.

באופן דומה, אפשר להגדיר מספר מקסימלי כדי להגביל את ההתאמה לעומס של המכונות בתגובה לבקשות נכנסות. אפשר להשתמש בהגדרה הזו כדי לשלוט בעלויות או להגביל את מספר החיבורים לשירות תומך, כמו מסד נתונים.

צמצום מספר ההפעלות במצב התחלתי (cold start)

כדי להגדיר את המספר המינימלי של מכונות לפונקציה בקוד המקור, משתמשים ב-method‏ runWith. השיטה הזו מקבלת אובייקט JSON שתואם לממשק RuntimeOptions, שמגדיר את הערך של minInstances. לדוגמה, הפונקציה הזו מגדירה מינימום של 5 מכונות שצריך לשמור במצב חם:

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
    });

כמה דברים שכדאי להביא בחשבון כשמגדירים ערך ל-minInstances:

  • אם Cloud Functions for Firebase מגדיל את האפליקציה מעבר להגדרה של minInstances, תהיה הפעלה במצב התחלתי (cold start) לכל מכונה מעל הסף הזה.
  • ההשפעה של הפעלות במצב התחלתי (cold start) היא הכי חמורה באפליקציות עם תנועה לא יציבה. אם באפליקציה יש תנועה עם שיאים חדים, ואתם מגדירים ערך minInstances גבוה מספיק כדי להפחית את ההפעלות במצב התחלתי בכל עלייה בתנועה, תראו הפחתה משמעותית בזמן האחזור. באפליקציות עם תנועה קבועה, הפעלות במצב התחלתי לא צפויות להשפיע באופן חמור על הביצועים.
  • הגדרת מספר מינימלי של מכונות יכולה להתאים לסביבות ייצור, אבל בדרך כלל כדאי להימנע מכך בסביבות בדיקה. כדי לצמצם את הפעולה לאפס בפרויקט הבדיקה, אבל עדיין להפחית את ההפעלות במצב התחלתי בפרויקט הייצור, אפשר להגדיר את minInstances על סמך משתנה הסביבה 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
        });
    

הגבלת המספר המקסימלי של מכונות לפונקציה

כדי להגדיר את מספר המכונות המקסימלי בקוד המקור של הפונקציה, משתמשים ב-method‏ runWith. השיטה הזו מקבלת אובייקט JSON שתואם לממשק RuntimeOptions, שמגדיר ערכים ל-maxInstances. לדוגמה, הפונקציה הזו מגדירה מגבלה של 100 מכונות כדי לא להעמיס על מסד נתונים היפותטי מדור קודם:

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

אם פונקציית HTTP מוגדלת עד למגבלה של maxInstances, בקשות חדשות נכנסות לתור למשך 30 שניות ואז נדחות עם קוד התגובה 429 Too Many Requests אם אין מכונה זמינה עד אז.

למידע נוסף על שיטות מומלצות לשימוש בהגדרות של מספר המכונות המקסימלי, קראו את השיטות המומלצות לשימוש ב-maxInstances.

הגדרת חשבון שירות

לחשבון השירות שמוגדר כברירת מחדל לפונקציות מהדור הראשון, PROJECT_ID@appspot.gserviceaccount.com (שנקרא חשבון השירות שמוגדר כברירת מחדל ב-App Engine), יש קבוצה רחבה של הרשאות שמאפשרות לכם לקיים אינטראקציה עם שירותים אחרים של Firebase ו-Google Cloud.

יכול להיות שתרצו לשנות את חשבון השירות שמוגדר כברירת מחדל ולהגביל פונקציה למשאבים המדויקים שנדרשים. כדי לעשות את זה, אתם יכולים ליצור חשבון שירות בהתאמה אישית ולהקצות אותו לפונקציה המתאימה באמצעות השיטה .runWith(). השיטה הזו מקבלת אובייקט עם אפשרויות הגדרה, כולל המאפיין 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!");
    });

הגדרת זמן קצוב לתפוגה והקצאת זיכרון

במקרים מסוימים, יכול להיות שלפונקציות יהיו דרישות מיוחדות לערך זמן קצוב לתפוגה ארוך או להקצאה גדולה של זיכרון. אפשר להגדיר את הערכים האלה במסוף Google Cloud או בקוד המקור של הפונקציה (ב-Firebase בלבד).

כדי להגדיר הקצאת זיכרון וזמן קצוב לתפוגה בקוד המקור של הפונקציות, משתמשים בפרמטר runWith שהוצג ב-Firebase SDK ל-Cloud Functions 2.0.0. אפשרות זמן הריצה הזו מקבלת אובייקט JSON שתואם לממשק RuntimeOptions, שמגדיר ערכים ל-timeoutSeconds ול-memory. לדוגמה, פונקציית האחסון הזו משתמשת בזיכרון בנפח 1GB, והזמן הקצוב לתפוגה שלה הוא 300 שניות:

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
    });

הערך המקסימלי של timeoutSeconds הוא 540, או 9 דקות. כמות הזיכרון שמוקצית לפונקציה תואמת למעבד (CPU) שמוקצה לפונקציה, כפי שמפורט ברשימה הבאה של ערכים חוקיים ל-memory:

  • 128MB — 200MHz
  • 256MB — 400MHz
  • 512MB — 800MHz
  • ‫1GB — 1.4 GHz
  • 2GB — 2.4 GHz
  • ‫4GB – 4.8GHz
  • ‫8GB – 4.8GHz

כדי להגדיר הקצאת זיכרון וזמן קצוב לתפוגה במסוף Google Cloud:

  1. במסוף Google Cloud, בוחרים באפשרות Cloud Functions בתפריט הימני.
  2. בוחרים פונקציה על ידי לחיצה על השם שלה ברשימת הפונקציות.
  3. לוחצים על סמל העריכה בתפריט העליון.
  4. בוחרים הקצאת זיכרון מהתפריט הנפתח Memory allocated.
  5. לוחצים על More כדי להציג את האפשרויות המתקדמות, ומזינים מספר שניות בתיבת הטקסט Timeout.
  6. לוחצים על שמירה כדי לעדכן את הפונקציה.