여러 함수 구성


Cloud Functions를 프로젝트에 통합하면 코드가 확장되어 여러 독립 함수를 포함할 수 있습니다. 단일 파일에 넣기에는 함수가 너무 많거나 팀마다 다른 함수 그룹을 배포하면 한 팀이 다른 팀의 함수를 덮어쓰거나 실수로 삭제할 위험이 있습니다. Cloud Functions는 함수를 더 쉽게 탐색하고 유지관리할 수 있도록 코드를 구성하는 다양한 방식을 제공합니다.

코드베이스에서 함수 구성

firebase.json에서 함수 구성 객체의 codebase 속성을 사용하여 단일 저장소 monorepo 설정 내에 있는 여러 저장소나 하위 패키지에서 대규모 함수 컬렉션을 관리할 수 있습니다.

# 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 v10.7.1 이상에서 지원됩니다.

여러 저장소 관리

codebase 속성을 사용하면 여러 저장소를 간단하게 관리할 수 있습니다. 같은 Firebase 프로젝트에 함수를 배포하는 저장소가 두 개 있는 경우를 살펴보겠습니다.

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

코드베이스 주석이 없으면 Firebase CLI에서 배포 시 다른 저장소에 정의된 함수를 삭제하라는 메시지가 표시되었을 것입니다.

$ (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"
}

코드베이스 주석을 사용하면 전용 저장소 외부에 정의된 함수를 삭제하라는 메시지가 Firebase CLI에 더 이상 표시되지 않습니다.

$ (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!

여러 소스 패키지 관리(monorepo)

codebase 속성을 사용하면 단일 저장소의 여러 소스 패키지를 간단하게 관리할 수 있습니다. 함수 정의가 여러 하위 패키지에 걸쳐 있는 Firebase 프로젝트 디렉터리가 있는 경우를 살펴보겠습니다.

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

이 설정은 다음 사용 사례에 적합합니다.

  • monorepo가 설정되어 있고 서로 다른 팀이 격리된 패키지에서 자체 함수 정의를 관리하고 있습니다.
  • 외부 종속 항목이 많고 초기화가 장기 실행되는 함수를 지연 시간에 민감한 다른 함수와 격리하려고 합니다.

이와 같은 monrepo 설정을 지원하려면 firebase.json에서 함수 구성을 여러 개 정의합니다.

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

이 구성을 통해 Firebase CLI는 단일 배포 명령어로 모든 패키지의 함수를 배포합니다.

$ 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-usageStatsmetrics-nightlyReport입니다.

함수 배포 시 작업을 단일 그룹으로 제한할 수 있습니다.


firebase deploy --only functions:metrics

다음 단계

Cloud Functions에 관해 자세히 알아보려면 다음을 참고하세요.