Как упорядочивать несколько функций (первое поколение)

По мере интеграции Cloud Functions в проект код может расширяться и содержать множество независимых функций. В одном файле может быть слишком много функций, или разные команды могут развертывать разные группы функций, что создает риск перезаписи или случайного удаления функций другой команды. В Cloud Functions можно организовать код разными способами, чтобы упростить навигацию и обслуживание функций.

Как упорядочивать функции в базах кода

Вы можете использовать свойство 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 версии 10.7.1 и более поздних.

Как управлять несколькими репозиториями

Свойство codebase позволяет упростить управление несколькими репозиториями. Рассмотрим случай, когда у вас есть два разных репозитория, которые развертывают функции в одном и том же проекте Firebase:

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

Без аннотаций в кодовой базе интерфейс командной строки 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)

Чтобы избежать этой проблемы, добавьте уникальную аннотацию codebase в раздел конфигурации функций файла firebase.json в каждом репозитории проекта:

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

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

Благодаря аннотациям базы кода интерфейс командной строки 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

Такая настройка подходит для следующих вариантов использования:

  • У вас настроен монорепозиторий, и разные команды управляют определениями функций в изолированном пакете.
  • У вас есть функция с сильной внешней зависимостью и длительной инициализацией, и вы хотите изолировать ее от других функций, чувствительных к задержкам.

Чтобы поддерживать такую конфигурацию монорепозитория, определите несколько конфигураций функций в файле firebase.json:

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

При такой конфигурации интерфейс командной строки 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)...
...

Вы также можете развернуть определенную базу кода:

$ 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":