deployment quotaに引っかかってCloudFunctionsのデプロイができない原因と対策

こんにちは。[もぐめっと](https://mogmet.com)です。

![IMG_3208.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42234/1dfdf65e-2df2-d984-2040-c6917999fec0.jpeg)
今回は埼玉クエストというところの一枚なのですが、最近テレビで夏でもスノーボードやスキーが楽しめる場所として紹介されたらしいのですが、そもそもスノボガチ勢じゃないとブラシで滑るって中々大変なので普通の人は気軽には来れないんじゃないか・・・と思ったりしてます。

本日はCloudFunctionsをデプロイする時に制限にひっかかったためその原因と対策を紹介します。

## 原因

ある日、CloudFunctionsをデプロイしようとしたら。。。

```
⚠  functions[******(asia-northeast1)]: Deployment error.
You have exceeded your deployment quota, please deploy your functions in batches by using the --only flag, and wait a few minutes before deploying again. Go to https://firebase.google.com/docs/cli/#deploy_specific_functions to learn more.
```

こんなエラーがでて一部CloudFunctionsのデプロイにこけてしまいました。

原因としてはエラーの表記通り、デプロイの制限に引っかかってしまったようです。

https://console.cloud.google.com/projectselector2/projectselector/iam-admin/quotas?service=cloudfunctions.googleapis.com&usage=ALL&supportedpurview=project

こちらより、割当の状況を確認すると夏のトマトが美味しく感じられるほど真っ赤になってました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42234/1d47534a-c085-7b93-a886-5e522941a470.png)

とくにWriteのAPIが顕著に引っかかってました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42234/53a6c8a2-2b07-70ce-c5c4-15b1f4bb7d3e.png)

デプロイするCloudFunctionsの数が増えてしまったせいと考えられます。

## 対策

https://stackoverflow.com/questions/56847616/firebase-functions-you-have-exceeded-your-deployment-quota/56847818

stack overflowには制限を増やせばいいよと入っているのですが、対象となっているAPIは残念ながらもう既にマックスまで振られていて変更ができませんでした。。。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42234/4bafbe6f-e0aa-fcd5-afb3-c9d3f068bf0a.png)

またマニュアルにもこのような一文が添えられています

https://firebase.google.com/docs/cli/#deploy_specific_functions

```
重要: 割り当てのエラーやその他のサーバーエラーが発生しないように、各デプロイ オペレーションの関数グループのサイズを 10 以下に制限してください。
```

ということで、デプロイを分割してやるようにしてみました。

方法としてはグループとしてCloudFunctionsを登録してグループごとにCloudFunctionsをデプロイできるようにしました。

```index.ts
import * as admin from 'firebase-admin'
admin.initializeApp()

const sugoiFunctions: { [key: string]: string } = {
  onUserCreated: './functions/onUserCreated'
...
}
const yabaiFunctions: { [key: string]: string } = {
  onContentCreated: './functions/onContentCreated'
...
}

function setExports(functions: { [key: string]: string }, rootKey: string) {
  exports[rootKey] = {}
  Object.keys(functions)
      .filter((name) => {
        return !process.env.FUNCTION_NAME || process.env.FUNCTION_NAME === name
      })
      .forEach((name) => {
        exports[rootKey][name] = require(functions[name]).default
      })
}

// 定義した内容をexportsに追加する
setExports(sugoiFunctions, 'sugoi')
setExports(yabaiFunctions, 'yabai')
```

```npm run deploy-functions```でfunctionsをデプロイできるようにしておきます。
functions以外をデプロイできるようにexceptを使ってその他のデプロイは行います。

```package.json
{
  "scripts": {
    "deploy": "./node_modules/.bin/firebase deploy -f --token=$FIREBASE_TOKEN --except functions",
    "deploy-functions": "./node_modules/.bin/firebase deploy --only functions:sugoi --token=$FIREBASE_TOKEN && ./node_modules/.bin/firebase deploy --only functions:yabai --token=$FIREBASE_TOKEN"
...
  }
}
```

これで分割デプロイができるようになりました！

## 注意点

分割したことにより、エンドポイント名も変更になるので、httpsCallableとかを使ってる場合は適宜、名前を変更しないといけなくなります。

例えば、今回の例でいうと```sugoi-onUserCreated```といった形でグループ名が頭につくようになりますので、フロント側や、firebase.jsonなどもかえてあげましょう。

また、グループを新規に追加した場合は、package.jsonも追加しないといけないので忘れないように注意です。

## まとめ

プロジェクトが大きくなってくると制限にひっかかるので、適宜分割してデプロイしてあげましょう！

最後に、[ワンナイト人狼オンライン](https://online.1nite-jinro.com/link/blog)というゲームを作ってます！よかったら遊んでね！

https://online.1nite-jinro.com/link/blog

他にも[Camecon](https://camecon.me/)や[Offcha](https://offcha.com/)といったサービスも作ってるのでよかったら使ってね！

https://camecon.me/

https://offcha.com/

また、チームビルディングや技術顧問、Firebaseの設計やアドバイスといったお話も受け付けてますので御用の方は弊社までお問い合わせください。

https://virapture.com/