ארגון מספר פונקציות


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

ארגון פונקציות ב-codebases

אפשר להשתמש במאפיין codebase של אובייקט הגדרת הפונקציות ב- firebase.json כדי לנהל אוסף גדול של פונקציות מאגרים או חבילות משנה בתוך הגדרת מונורפו אחת של מאגר:

# firebase.json
"functions": {
  "codebase": "my-codebase"
  # NOTE: Codebase must be less than 63 characters and can contain only
  # lowercase letters, numeric characters, underscores, and dashes.
}

הנכס codebase נתמך ב-Firebase CLI גרסה 10.7.1 ואילך.

ניהול של כמה מאגרים

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

$  tree .
├── repoA
│   ├── firebase.json
│   └── functions
│       ├── index.js
│       └── package.json
└── repoB
    ├── firebase.json
    └── functions
        ├── index.js
        └── package.json

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

$ (cd repoA && firebase deploy --only functions)
...
i  functions: preparing functions directory for uploading...
  functions: functions folder uploaded successfully
The following functions are found in your project but do not exist in your local source code:
        fn1FromRepoB
        fn2FromRepoB
        ...
? Would you like to proceed with deletion? Selecting no will continue the rest of the deployments. (y/N)

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

# repoA/firebase.json
"functions": {
  "codebase": "repo-a"
}

# repoB/firebase.json
"functions": {
  "codebase": "repo-b"
}

עם הערת Codebase, ב-CLI של Firebase לא מופיעה יותר בקשה למחוק מוגדרות מחוץ למאגר המיידי שלכם:

$ (cd repoA && firebase deploy --only functions)
...
i  functions: preparing functions directory for uploading...
  functions: functions folder uploaded successfully
#  Gleefully ignores functions from repoB
i  functions: creating Node.js 16 function fnFromRepoA (us-central1)...
  Deploy Complete!

ניהול חבילות מקור מרובות (מונורפו)

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

$  tree .
├── firebase.json
├── teamA
│   ├── index.js
│   └── package.json
└── teamB
    ├── index.js
    └── package.json

ההגדרה הזו מתאימה לתרחישים הבאים לדוגמה:

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

כדי לתמוך בהגדרת Monrepo בצורה הזו, צריך להגדיר כמה הגדרות של פונקציות ב-firebase.json:

"functions": [
  {
    "source": "teamA",
    "codebase": "team-a"
  },
  {
    "source": "teamB",
    "codebase": "team-b"
  },
]

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

$ firebase deploy --only functions
i  deploying functions
i  functions: preparing codebase team-a for deployment
i  functions: preparing codebase team-b for deployment
i  functions: creating Node.js 16 function team-a:helloATeam(us-central1)...
i  functions: creating Node.js 16 function team-b:helloBTeam(us-central1)...
...

אפשר גם לפרוס קוד בסיס (codebase) ספציפי:

$ firebase deploy --only functions:team-b
i  deploying functions
i  functions: preparing codebase team-b for deployment
i  functions: updating Node.js 16 function team-b:helloBTeam(us-central1)...
...

כתיבת פונקציות במספר קבצים

בתחילת העבודה עם Cloud Functions, ייתכן בקובץ יחיד:

index.js

const functions = require('firebase-functions/v1');
exports.foo = functions.https.onRequest((request, response) => {
  // ...
});
exports.bar = functions.https.onRequest((request, response) => {
  // ...
});

main.py

from firebase_functions import https_fn

@https_fn.on_request()
def foo(req: https_fn.Request) -> https_fn.Response:
    return https_fn.Response("Hello foo!")

@https_fn.on_request()
def bar(req: https_fn.Request) -> https_fn.Response:
    return https_fn.Response("Hello bar!")

לפעמים קשה לנהל את זה בכמה פונקציות. במקום זאת, שתהיה אפשרות לשמור את כל הלוגיקה של כל פונקציה בקובץ נפרד ולהשתמש את קובץ המקור כרשימה של פעולות ייצוא:

Node.js

foo.js

const functions = require('firebase-functions/v1');
exports.foo = functions.https.onRequest((request, response) => {
  // ...
});

bar.js

const functions = require('firebase-functions/v1');
exports.bar = functions.https.onRequest((request, response) => {
  // ...
});

index.js

const foo = require('./foo');
const bar = require('./bar');
exports.foo = foo.foo;
exports.bar = bar.bar;

Python

foo.py

from firebase_functions import https_fn

@https_fn.on_request()
def foo(req: https_fn.Request) -> https_fn.Response:
    return https_fn.Response("Hello foo!")

bar.py

from firebase_functions import https_fn

@https_fn.on_request()
def bar(req: https_fn.Request) -> https_fn.Response:
    return https_fn.Response("Hello foo!")

main.py

from fn_impl.foo import *
from fn_impl.bar import *

ההגדרה הזו מבוססת על המבנה של ספריית פרויקט כמו:

my-project
├── firebase.json
└── functions
    ├── fn_impl
    │   ├── __init__.py
    │   ├── foo.py
    │   └── bar.py
    ├── main.py
    └── requirements.txt

fn_impl: יכול להיות כל שם

__init__.py: שדה חובה, אבל יכול להיות ריק

קיבוץ פונקציות

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

metrics.js


const functions = require('firebase-functions/v1');
exports.usageStats = functions.https.onRequest((request, response) => {
  // ...
});
exports.nightlyReport = functions.https.onRequest((request, response) => {
  // ...
});

אפשר להוסיף את הפונקציות האלה לקבוצה כשמייצאים אותן לקובץ index.js:

index.js


// Export both functions from metrics.js in the "metrics" group:
//  - metrics-usageStats
//  - metrics-nightlyReport
exports.metrics = require('./metrics');

כשפונקציות יפורסמו, שם הקבוצה שלהן יופיע כתחילית של השם שלהן. לדוגמה, הפונקציות יהיו בשמות metrics-usageStats ו-metrics-nightlyReport.

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


firebase deploy --only functions:metrics

השלבים הבאים

למידע נוסף על Cloud Functions, ראו: