Use Cases

Claude Code × GCP Cloud Functions 完全ガイド|サーバーレス関数を爆速開発

GCP Cloud FunctionsをClaude Codeで効率化。HTTP/Pub/Sub/Firestoreトリガーの実装からローカルテスト・デプロイ自動化まで、Masaの実務経験をもとに実例コードで解説。

Cloud Run は大げさ、だから Cloud Functions を選んだ

claudecode-lab.com を運営している Masa です。

GCP でサーバーレスを使いはじめたとき、最初は Cloud Run を検討していました。コンテナを使えて柔軟性が高い——しかし、**「Webhook を 1 本受け取るだけ」「夜中に 1 回バッチを回すだけ」**という用途には明らかにオーバースペックでした。Dockerfile を書き、Cloud Build を設定し、サービスアカウントを作り……その手間に対してやりたいことが小さすぎる。

そこで乗り換えたのが Cloud Functions (第 2 世代 / Gen2) です。関数 1 本をデプロイするだけで HTTPS エンドポイントが立ち上がり、使わなければ課金されない。AWS Lambda の感覚で使えて、GCP エコシステム (Pub/Sub・Firestore・Cloud Scheduler) とのシームレスな統合が魅力です。

ただ、Cloud Functions のコードを書くたびに「トリガー設定どう書くんだっけ」「Functions Framework のローカル起動コマンドは?」と毎回ドキュメントを引いていました。それを解消したのが Claude Code です。今では Cloud Functions 関連のコードは 90% 以上が Claude Code 生成で、私はレビューと実行確認に集中できています。

この記事では、私が実際に使っている Cloud Functions × Claude Code のパターンをステップ別にすべて公開します。


なぜ GCP Cloud Functions に Claude Code が向いているのか

Cloud Functions (Gen2) は Cloud Run をベースに動いており、最大 9 分のタイムアウト・最大 16 GB メモリ・最大 1000 並列インスタンスに対応しています。Gen1 の「5 分・2 GB」という制約を大幅に超えたことで、実用範囲が一気に広がりました。

Claude Code との相性が良い理由は 3 つあります。

  1. 定型コードが多い: トリガー定義・型付けされたリクエスト/レスポンス処理・Secret Manager 連携などは毎回似たパターンで書く必要があり、Claude Code が得意とする「パターン補完」がよく機能します。
  2. デプロイコマンドが長い: gcloud functions deploy に渡すオプションは 10 個以上になることが多く、毎回手打ちするのは苦痛です。Claude Code にテンプレートとして管理させることで抜け漏れを防げます。
  3. テストとローカル開発の設定が面倒: Functions Framework のセットアップや curl でのリクエスト模擬は初見だと詰まりやすいポイントで、Claude Code が一括で用意してくれます。

Step 1: HTTP トリガー関数の実装

Cloud Functions で最もよく使うのが HTTP トリガーです。HTTPS エンドポイントが自動で用意され、API や Webhook として使えます。

Claude Code へのプロンプト

GCP Cloud Functions Gen2 (TypeScript) でHTTPトリガー関数を作って。
- リクエストボディに { userId: string, action: string } を受け取る
- Authorization ヘッダーで Bearer トークンを検証する
- Firestore にログを書き込む
- エラーは JSON 形式で返す
- Functions Framework 向けの export 形式で書く

生成されたコード

import { http, HttpFunction } from "@google-cloud/functions-framework";
import { Request, Response } from "express";
import { Firestore } from "@google-cloud/firestore";

const db = new Firestore();
const VALID_TOKEN = process.env.API_SECRET_TOKEN;

// リクエストボディの型定義
interface ActionRequest {
  userId: string;
  action: string;
}

// レスポンスの型定義
interface ActionResponse {
  success: boolean;
  message: string;
  logId?: string;
}

const handleAction: HttpFunction = async (req: Request, res: Response) => {
  // CORSヘッダーを設定
  res.set("Access-Control-Allow-Origin", "*");
  if (req.method === "OPTIONS") {
    res.set("Access-Control-Allow-Methods", "POST");
    res.set("Access-Control-Allow-Headers", "Authorization, Content-Type");
    res.status(204).send("");
    return;
  }

  // POST のみ許可
  if (req.method !== "POST") {
    res.status(405).json({ success: false, message: "Method Not Allowed" });
    return;
  }

  // Bearer トークン検証
  const authHeader = req.headers.authorization ?? "";
  if (!authHeader.startsWith("Bearer ") || authHeader.slice(7) !== VALID_TOKEN) {
    res.status(401).json({ success: false, message: "Unauthorized" });
    return;
  }

  // ボディバリデーション
  const body = req.body as Partial<ActionRequest>;
  if (!body.userId || !body.action) {
    res.status(400).json({
      success: false,
      message: "userId and action are required",
    });
    return;
  }

  try {
    // Firestore にログ書き込み
    const logRef = await db.collection("action_logs").add({
      userId: body.userId,
      action: body.action,
      timestamp: new Date(),
      ip: req.ip,
    });

    const response: ActionResponse = {
      success: true,
      message: "Action logged successfully",
      logId: logRef.id,
    };
    res.status(200).json(response);
  } catch (err) {
    console.error("Firestore write error:", err);
    res.status(500).json({ success: false, message: "Internal Server Error" });
  }
};

http("handleAction", handleAction);

package.json

{
  "name": "cloud-functions-sample",
  "version": "1.0.0",
  "main": "dist/index.js",
  "scripts": {
    "build": "tsc",
    "start": "npx @google-cloud/functions-framework --target=handleAction",
    "dev": "npx @google-cloud/functions-framework --target=handleAction --port=8080"
  },
  "dependencies": {
    "@google-cloud/firestore": "^7.0.0",
    "@google-cloud/functions-framework": "^3.0.0"
  },
  "devDependencies": {
    "@types/express": "^4.17.0",
    "typescript": "^5.0.0"
  }
}

ポイント: http() で関数名を登録することで、Functions Framework がローカルでもクラウドでも同じエントリポイントで動きます。環境変数 API_SECRET_TOKEN は後述の Secret Manager から取得します。


Step 2: Pub/Sub トリガー関数(非同期イベント処理)

Cloud Pub/Sub は GCP の非同期メッセージングサービスです。「注文完了後にメールを送る」「画像アップロード後にサムネイル生成する」といった非同期処理に使います。

Claude Code へのプロンプト

Cloud Functions Gen2 で Pub/Sub トリガーの関数を TypeScript で作って。
- トピック名: image-uploaded
- メッセージデータに { bucketName: string, filePath: string } が入っている (base64エンコード)
- Cloud Storage からファイルメタデータを取得してログ出力
- 処理失敗時はメッセージを再試行させる (例外をスローする)

生成されたコード

import { cloudEvent, CloudEvent } from "@google-cloud/functions-framework";
import { MessagePublishedData } from "@google/events/cloud/pubsub/v1/MessagePublishedData";
import { Storage } from "@google-cloud/storage";

const storage = new Storage();

interface ImageUploadedMessage {
  bucketName: string;
  filePath: string;
}

cloudEvent<MessagePublishedData>("handleImageUploaded", async (event: CloudEvent<MessagePublishedData>) => {
  const base64Data = event.data?.message?.data;
  if (!base64Data) {
    // データがない場合は再試行しない (nackではなくackで捨てる)
    console.warn("No message data received, skipping");
    return;
  }

  // base64 → JSON デコード
  const rawJson = Buffer.from(base64Data, "base64").toString("utf-8");
  let payload: ImageUploadedMessage;
  try {
    payload = JSON.parse(rawJson) as ImageUploadedMessage;
  } catch {
    console.error("Invalid JSON in Pub/Sub message:", rawJson);
    return; // パースエラーは再試行しても無駄なので捨てる
  }

  const { bucketName, filePath } = payload;
  console.log(`Processing: gs://${bucketName}/${filePath}`);

  try {
    // Cloud Storage からメタデータ取得
    const [metadata] = await storage.bucket(bucketName).file(filePath).getMetadata();
    console.log("File metadata:", {
      name: metadata.name,
      size: metadata.size,
      contentType: metadata.contentType,
      updated: metadata.updated,
    });

    // ここにサムネイル生成などのビジネスロジックを追加
    console.log(`Successfully processed: ${filePath}`);
  } catch (err) {
    // 例外をスローすることで Pub/Sub がメッセージを再試行する
    console.error(`Failed to process ${filePath}:`, err);
    throw err;
  }
});

ポイント: Pub/Sub トリガーでは「例外をスローする = メッセージを再試行させる」「正常リターン = メッセージを確認済みとして捨てる」というセマンティクスになります。パースエラーのような「何度試しても失敗する」エラーは例外をスローせずに return することで、デッドレターキューに詰まるのを防げます。


Step 3: Firestore トリガー関数(ドキュメント変更に反応)

Firestore のドキュメントが作成・更新・削除されたタイミングで関数を実行できます。ユーザー登録時のウェルカムメール送信や、データ変更の監査ログ記録などに使います。

Claude Code へのプロンプト

Cloud Functions Gen2 で Firestore トリガーの関数を TypeScript で作って。
- コレクション: users/{userId}
- ドキュメント作成時にウェルカムメールの送信ジョブをキューに積む
- ドキュメント更新時に変更フィールドをログに記録する
- 削除時はアーカイブコレクションにコピーする

生成されたコード

import { onDocumentWritten, Change, FirestoreEvent } from "firebase-functions/v2/firestore";
import { QueryDocumentSnapshot } from "firebase-admin/firestore";
import * as admin from "firebase-admin";

admin.initializeApp();
const db = admin.firestore();

interface UserDocument {
  email: string;
  name: string;
  createdAt: FirebaseFirestore.Timestamp;
  plan: "free" | "pro";
}

export const onUserWrite = onDocumentWritten(
  "users/{userId}",
  async (event: FirestoreEvent<Change<QueryDocumentSnapshot> | undefined, { userId: string }>) => {
    const userId = event.params.userId;
    const before = event.data?.before;
    const after = event.data?.after;

    // 作成イベント
    if (!before?.exists && after?.exists) {
      const userData = after.data() as UserDocument;
      console.log(`New user created: ${userId}, email: ${userData.email}`);

      // Pub/Sub にウェルカムメール送信ジョブをキュー
      await db.collection("email_queue").add({
        to: userData.email,
        template: "welcome",
        data: { name: userData.name },
        createdAt: admin.firestore.FieldValue.serverTimestamp(),
        status: "pending",
      });
      return;
    }

    // 更新イベント
    if (before?.exists && after?.exists) {
      const beforeData = before.data() as UserDocument;
      const afterData = after.data() as UserDocument;

      // 変更されたフィールドを特定してログ記録
      const changedFields = Object.keys(afterData).filter(
        (key) => JSON.stringify(beforeData[key as keyof UserDocument]) !==
                 JSON.stringify(afterData[key as keyof UserDocument])
      );

      if (changedFields.length > 0) {
        await db.collection("audit_logs").add({
          userId,
          changedFields,
          before: beforeData,
          after: afterData,
          timestamp: admin.firestore.FieldValue.serverTimestamp(),
        });
        console.log(`User ${userId} updated fields: ${changedFields.join(", ")}`);
      }
      return;
    }

    // 削除イベント
    if (before?.exists && !after?.exists) {
      const userData = before.data() as UserDocument;
      // アーカイブコレクションにコピー
      await db.collection("deleted_users").doc(userId).set({
        ...userData,
        deletedAt: admin.firestore.FieldValue.serverTimestamp(),
      });
      console.log(`User ${userId} archived`);
    }
  }
);

ポイント: Firestore トリガーは firebase-functions/v2 パッケージを使います。before.existsafter.exists の組み合わせで作成・更新・削除を判別できます。削除イベントを使ったソフトデリート代わりのアーカイブは、データ復旧の安全網として非常に有効です。


Step 4: Cloud Scheduler + Cloud Functions(定時実行バッチ)

「毎朝 9 時に前日の集計データを計算する」「1 時間おきに外部 API のデータを同期する」といった定時実行バッチは、Cloud Scheduler と HTTP トリガー関数を組み合わせて実現します。

Claude Code へのプロンプト

Cloud Scheduler から叩かれる Cloud Functions のバッチ関数を TypeScript で書いて。
- 毎日 AM 2:00 (JST) に実行
- Firestore の orders コレクションから前日の注文を集計
- 結果を daily_summaries コレクションに保存
- Cloud Scheduler からのリクエストのみ受け付ける (OIDC トークン検証)

生成されたコード

import { http, HttpFunction } from "@google-cloud/functions-framework";
import { Request, Response } from "express";
import { Firestore, Timestamp } from "@google-cloud/firestore";
import { OAuth2Client } from "google-auth-library";

const db = new Firestore();
const authClient = new OAuth2Client();
const SERVICE_ACCOUNT_EMAIL = process.env.SCHEDULER_SERVICE_ACCOUNT!;

// Cloud Scheduler の OIDC トークンを検証
async function verifySchedulerToken(req: Request): Promise<boolean> {
  const authHeader = req.headers.authorization ?? "";
  if (!authHeader.startsWith("Bearer ")) return false;
  const token = authHeader.slice(7);
  try {
    const ticket = await authClient.verifyIdToken({
      idToken: token,
      audience: process.env.FUNCTION_URL!, // Cloud Functions の URL
    });
    const payload = ticket.getPayload();
    return payload?.email === SERVICE_ACCOUNT_EMAIL;
  } catch {
    return false;
  }
}

const dailySummaryBatch: HttpFunction = async (req: Request, res: Response) => {
  // OIDC トークン検証
  const isValid = await verifySchedulerToken(req);
  if (!isValid) {
    res.status(403).json({ error: "Forbidden: invalid scheduler token" });
    return;
  }

  // 昨日の開始・終了時刻を計算 (JST)
  const now = new Date();
  const jstOffset = 9 * 60 * 60 * 1000;
  const jstNow = new Date(now.getTime() + jstOffset);
  const yesterdayStart = new Date(jstNow);
  yesterdayStart.setHours(0, 0, 0, 0);
  yesterdayStart.setDate(yesterdayStart.getDate() - 1);
  const yesterdayEnd = new Date(yesterdayStart);
  yesterdayEnd.setHours(23, 59, 59, 999);

  // UTCに戻す
  const startUTC = new Date(yesterdayStart.getTime() - jstOffset);
  const endUTC = new Date(yesterdayEnd.getTime() - jstOffset);

  try {
    // 前日の注文を集計
    const ordersSnapshot = await db
      .collection("orders")
      .where("createdAt", ">=", Timestamp.fromDate(startUTC))
      .where("createdAt", "<=", Timestamp.fromDate(endUTC))
      .get();

    let totalAmount = 0;
    let totalCount = 0;
    const planBreakdown: Record<string, number> = {};

    ordersSnapshot.forEach((doc) => {
      const data = doc.data();
      totalAmount += data.amount ?? 0;
      totalCount += 1;
      const plan = data.plan ?? "unknown";
      planBreakdown[plan] = (planBreakdown[plan] ?? 0) + 1;
    });

    const summaryDate = yesterdayStart.toISOString().slice(0, 10); // YYYY-MM-DD
    await db.collection("daily_summaries").doc(summaryDate).set({
      date: summaryDate,
      totalAmount,
      totalCount,
      planBreakdown,
      generatedAt: new Date(),
    });

    console.log(`Daily summary for ${summaryDate}: count=${totalCount}, amount=${totalAmount}`);
    res.status(200).json({ success: true, date: summaryDate, totalCount, totalAmount });
  } catch (err) {
    console.error("Batch error:", err);
    res.status(500).json({ error: "Internal server error" });
  }
};

http("dailySummaryBatch", dailySummaryBatch);

Cloud Scheduler の設定 (gcloud コマンド):

# スケジューラーが使うサービスアカウントを作成
gcloud iam service-accounts create cloud-scheduler-sa \
  --display-name="Cloud Scheduler Service Account"

# Cloud Functions の URL を取得
FUNCTION_URL=$(gcloud functions describe dailySummaryBatch \
  --region=asia-northeast1 \
  --format="value(serviceConfig.uri)")

# スケジュールジョブを作成 (毎日 AM 2:00 JST = UTC 17:00)
gcloud scheduler jobs create http daily-summary-job \
  --location=asia-northeast1 \
  --schedule="0 17 * * *" \
  --uri="$FUNCTION_URL" \
  --http-method=POST \
  --oidc-service-account-email=cloud-scheduler-sa@${PROJECT_ID}.iam.gserviceaccount.com \
  --oidc-token-audience="$FUNCTION_URL"

Step 5: ローカルテスト(Functions Framework)

Cloud Functions のローカルテストは Functions Framework を使います。本番と同じコードをローカルで動かせるため、デプロイなしに開発サイクルを回せます。

Functions Framework のセットアップ

npm install --save-dev @google-cloud/functions-framework

tsconfig.json

{
  "compilerOptions": {
    "target": "ES2020",
    "module": "commonjs",
    "lib": ["ES2020"],
    "outDir": "./dist",
    "rootDir": "./src",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules", "dist"]
}

ローカル起動と動作確認

# TypeScript をビルド
npm run build

# Functions Framework でローカル起動
npx @google-cloud/functions-framework --target=handleAction --port=8080

# 別ターミナルで HTTP リクエストを送信
curl -X POST http://localhost:8080 \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer your-local-test-token" \
  -d '{"userId": "user-123", "action": "login"}'

Pub/Sub トリガーのローカルテスト

Pub/Sub トリガーはローカルでのエミュレートが少し手間です。Claude Code にテスト用 curl コマンドを生成してもらうと一発です。

# Pub/Sub メッセージをエミュレート (base64エンコードしたJSONを送る)
MESSAGE_DATA=$(echo -n '{"bucketName":"my-bucket","filePath":"images/test.png"}' | base64)

curl -X POST http://localhost:8080 \
  -H "Content-Type: application/json" \
  -d "{
    \"specversion\": \"1.0\",
    \"type\": \"google.cloud.pubsub.topic.v1.messagePublished\",
    \"source\": \"//pubsub.googleapis.com/projects/my-project/topics/image-uploaded\",
    \"id\": \"test-event-id\",
    \"data\": {
      \"message\": {
        \"data\": \"$MESSAGE_DATA\",
        \"attributes\": {}
      }
    }
  }"

Step 6: デプロイ自動化(gcloud + GitHub Actions)

手動デプロイを繰り返すのはミスのもとです。Claude Code に CI/CD パイプラインを生成してもらいます。

gcloud デプロイコマンド (雛形)

gcloud functions deploy handleAction \
  --gen2 \
  --runtime=nodejs22 \
  --region=asia-northeast1 \
  --source=. \
  --entry-point=handleAction \
  --trigger-http \
  --allow-unauthenticated \
  --memory=512Mi \
  --timeout=60s \
  --min-instances=0 \
  --max-instances=100 \
  --set-secrets="API_SECRET_TOKEN=api-secret-token:latest" \
  --set-env-vars="NODE_ENV=production"

GitHub Actions ワークフロー

# .github/workflows/deploy-functions.yml
name: Deploy Cloud Functions

on:
  push:
    branches: [main]
    paths:
      - "functions/**"

jobs:
  deploy:
    runs-on: ubuntu-latest
    permissions:
      contents: read
      id-token: write # Workload Identity Federation 用

    steps:
      - uses: actions/checkout@v4

      - name: Authenticate to Google Cloud
        uses: google-github-actions/auth@v2
        with:
          workload_identity_provider: ${{ secrets.WIF_PROVIDER }}
          service_account: ${{ secrets.WIF_SERVICE_ACCOUNT }}

      - name: Set up Cloud SDK
        uses: google-github-actions/setup-gcloud@v2

      - name: Set up Node.js
        uses: actions/setup-node@v4
        with:
          node-version: "22"
          cache: "npm"
          cache-dependency-path: functions/package-lock.json

      - name: Install dependencies & build
        working-directory: functions
        run: |
          npm ci
          npm run build

      - name: Deploy handleAction
        working-directory: functions
        run: |
          gcloud functions deploy handleAction \
            --gen2 \
            --runtime=nodejs22 \
            --region=asia-northeast1 \
            --source=dist \
            --entry-point=handleAction \
            --trigger-http \
            --allow-unauthenticated \
            --memory=512Mi \
            --timeout=60s \
            --set-secrets="API_SECRET_TOKEN=api-secret-token:latest" \
            --project=${{ secrets.GCP_PROJECT_ID }}

ポイント: Workload Identity Federation (WIF) を使うことで、サービスアカウントキーを GitHub Secrets に保存せずに認証できます。セキュリティ的に大きなメリットです。Claude Code に「Workload Identity Federation を使った GitHub Actions の設定を書いて」と依頼すると、プロバイダー作成からバインディング設定まで一括で出してくれます。


落とし穴 4 選

実際に Cloud Functions を本番運用する中で踏んだ罠をまとめます。

落とし穴 1: コールドスタートによるタイムアウト

症状: リクエストが散発的に遅い。夜間は特にひどい。

原因: インスタンスがゼロの状態からの起動(コールドスタート)が 2〜5 秒かかる。

対策:

# 最小インスタンスを 1 に設定(コールドスタートを排除)
gcloud functions deploy handleAction \
  --min-instances=1  # これだけで大幅改善

ただし --min-instances=1 は常時 1 インスタンスが起動し続けるため、料金が発生します。SLA 要件と費用のトレードオフで判断してください。私の場合、ユーザー向け API は min-instances=1、バッチ処理は min-instances=0 と使い分けています。

落とし穴 2: タイムアウト 9 分制限を超える処理

症状: 大量データ処理のバッチが途中でタイムアウトして中断される。

原因: Cloud Functions Gen2 の最大タイムアウトは 9 分 (540 秒) です。これを超える処理は設計を変える必要があります。

対策:

// NG: 1 万件を一括処理 (タイムアウトリスク大)
const allDocs = await db.collection("orders").get(); // 全件取得

// OK: Pub/Sub でチャンク分割して非同期処理
const CHUNK_SIZE = 500;
for (let i = 0; i < totalCount; i += CHUNK_SIZE) {
  await pubsubClient.topic("process-orders-chunk").publishMessage({
    json: { offset: i, limit: CHUNK_SIZE },
  });
}
// 各チャンクを別の Cloud Functions インスタンスで並列処理

落とし穴 3: Secret Manager の権限設定漏れ

症状: デプロイは成功するが、実行時に Permission denied エラーが発生する。

原因: Cloud Functions の実行サービスアカウントに Secret Manager へのアクセス権がない。

対策:

# Cloud Functions のデフォルトサービスアカウントに権限付与
PROJECT_ID=$(gcloud config get-value project)
PROJECT_NUMBER=$(gcloud projects describe $PROJECT_ID --format="value(projectNumber)")

gcloud projects add-iam-policy-binding $PROJECT_ID \
  --member="serviceAccount:${PROJECT_NUMBER}[email protected]" \
  --role="roles/secretmanager.secretAccessor"

これを --set-secrets オプションと組み合わせることで、コードに秘密情報を書かずに環境変数として受け取れます。

落とし穴 4: メモリ不足によるクラッシュ

症状: 画像処理や大きな JSON を扱うと OOM (Out of Memory) でクラッシュする。

原因: Cloud Functions のデフォルトメモリは 256MB です。Node.js のヒープは実際にはもう少し使えますが、重い処理では簡単に超えます。

対策:

# メモリとCPUを引き上げる (Gen2ではCPUも連動して増加)
gcloud functions deploy processImage \
  --memory=2Gi \  # 2GB に引き上げ
  --cpu=2         # CPU コア数も指定可能 (Gen2のみ)

Claude Code に「この関数がどれくらいメモリを使うか見積もって」と聞くと、処理するデータ量から適切なメモリ設定を提案してくれます。


まとめ: Cloud Functions × Claude Code の組み合わせ表

トリガーユースケース主な注意点
HTTPWebhook・API エンドポイント認証・CORS・タイムアウト設定
Pub/Sub非同期イベント処理base64 デコード・再試行設計
Firestoreデータ変更への反応無限ループに注意
Cloud Scheduler定時バッチOIDC 検証・タイムゾーン管理
Claude Code の活用場面効果
初期実装の雛形生成実装時間を 1/3 に短縮
gcloud コマンド生成オプション漏れを防止
GitHub Actions 設定CI/CD を即日構築
テスト用 curl 生成ローカルデバッグを高速化
エラーメッセージの診断原因特定が即座に完了

私の実感: Cloud Functions の「最初の 1 関数」を動かすまでの時間が、Claude Code 導入前は半日かかっていたものが、今では 30 分以内 に完了します。ドキュメントを引く時間が Claude Code との会話に置き換わり、手が止まらなくなります。


この記事で紹介した内容を実際に試した結果

claudecode-lab.com では、現在 7 本の Cloud Functions が本番稼働しています。内訳は「Stripe Webhook 処理 (HTTP)」「画像リサイズ (Pub/Sub)」「Firestore 変更通知 (Firestore トリガー)」「日次集計バッチ (Cloud Scheduler)」などです。

コールドスタート対策として主要な 3 関数に --min-instances=1 を設定したところ、P99 レスポンスタイムが 4.2 秒 → 0.8 秒に改善しました。月のコストは 1 インスタンス常時稼働で約 $3〜5/月 増加しましたが、ユーザー体験の向上を考えれば十分なトレードオフです。

今後は Eventarc トリガー(Cloud Storage / BigQuery イベント)の活用も増やしていく予定です。


関連記事

#claude-code #gcp #cloud-functions #typescript #serverless #pubsub
無料プレゼント

無料PDF: Claude Code はじめてのチートシート

まずは無料PDFで基本コマンドと最初の使い方をまとめて確認してください。登録後はそのままテンプレート集や導入相談にも進めます。

スパムは送りません。登録情報は厳重に管理します。

Claude Codeを仕事で使える形にしませんか?

無料PDFで基礎を固めたあと、すぐ使えるテンプレート集で試し、必要なら業務自動化や導入相談まで進められます。

Masa

この記事を書いた人

Masa

現役DX室長|Claude Code でゼロから多言語AI技術メディア運営中。実務直結の自動化、AI開発相談・研修受付中。

PR

関連書籍・参考図書

この記事のテーマに関連する書籍を楽天ブックスで探せます。

※ 当サイトは楽天市場のアフィリエイトプログラムに参加しています。上記リンクから商品をご購入いただくと、運営者に紹介料が支払われる場合があります。