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

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

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

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

firebase deploy --only functions

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

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

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

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

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

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

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

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

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

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

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

    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

‫Firebase SDK ל-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.

קביעת אופן הפעולה של שינוי הגודל

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

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

הפחתת מספר ההפעלות במצב התחלתי

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

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

כדי להגדיר את מספר המכונות המקסימלי בקוד המקור של הפונקציה, משתמשים בשיטה 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 דקות. כמות הזיכרון שמוקצה לפונקציה תואמת למעבד שהוקצה לפונקציה, כפי שמפורט ברשימת הערכים התקינים הבאה של memory:

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

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

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