Use Cases

Claude Code × GCP Cloud Functions Panduan Lengkap | Pengembangan Serverless Super Cepat

Optimalkan GCP Cloud Functions dengan Claude Code. Implementasikan trigger HTTP/Pub/Sub/Firestore, pengujian lokal, dan otomatisasi deployment dengan contoh kode nyata dari pengalaman Masa.

Cloud Run Terlalu Berlebihan — Itulah Mengapa Saya Memilih Cloud Functions

Saya Masa, pengembang di balik claudecode-lab.com.

Ketika saya mulai menggunakan GCP Serverless, saya mempertimbangkan Cloud Run. Fleksibel dan berbasis container — tetapi untuk tugas seperti “hanya menerima satu webhook” atau “menjalankan batch sekali di malam hari”, itu jelas terlalu berlebihan. Itulah mengapa saya beralih ke Cloud Functions Gen2.

Dengan Claude Code, lebih dari 90% kode Cloud Functions saya dibuat secara otomatis.


Langkah 1: Fungsi dengan Trigger HTTP

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;
}

const handleAction: HttpFunction = async (req: Request, res: Response) => {
  // Atur header 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;
  }

  // Hanya izinkan POST
  if (req.method !== "POST") {
    res.status(405).json({ success: false, message: "Metode Tidak Diizinkan" });
    return;
  }

  // Validasi Bearer token
  const authHeader = req.headers.authorization ?? "";
  if (!authHeader.startsWith("Bearer ") || authHeader.slice(7) !== VALID_TOKEN) {
    res.status(401).json({ success: false, message: "Tidak Diotorisasi" });
    return;
  }

  const body = req.body as Partial<ActionRequest>;
  if (!body.userId || !body.action) {
    res.status(400).json({ success: false, message: "userId dan action diperlukan" });
    return;
  }

  try {
    const logRef = await db.collection("action_logs").add({
      userId: body.userId,
      action: body.action,
      timestamp: new Date(),
      ip: req.ip,
    });
    res.status(200).json({ success: true, message: "Aksi dicatat", logId: logRef.id });
  } catch (err) {
    console.error("Kesalahan penulisan Firestore:", err);
    res.status(500).json({ success: false, message: "Kesalahan Server Internal" });
  }
};

http("handleAction", handleAction);

Langkah 2: Fungsi dengan Trigger Pub/Sub

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) {
    console.warn("Tidak ada data pesan diterima, melewati");
    return;
  }

  const rawJson = Buffer.from(base64Data, "base64").toString("utf-8");
  let payload: ImageUploadedMessage;
  try {
    payload = JSON.parse(rawJson) as ImageUploadedMessage;
  } catch {
    console.error("JSON tidak valid dalam pesan Pub/Sub:", rawJson);
    return;
  }

  const { bucketName, filePath } = payload;
  try {
    const [metadata] = await storage.bucket(bucketName).file(filePath).getMetadata();
    console.log("Metadata file:", { nama: metadata.name, ukuran: metadata.size });
  } catch (err) {
    // Melempar exception menyebabkan Pub/Sub mencoba ulang pesan
    console.error(`Gagal memproses ${filePath}:`, err);
    throw err;
  }
});

Langkah 3: Pengujian Lokal dan Deployment

# Mulai lokal
npm run build
npx @google-cloud/functions-framework --target=handleAction --port=8080

# Kirim permintaan pengujian
curl -X POST http://localhost:8080 \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer test-token" \
  -d '{"userId": "user-123", "action": "login"}'

# Deploy ke GCP
gcloud functions deploy handleAction \
  --gen2 \
  --runtime=nodejs22 \
  --region=asia-southeast2 \
  --source=. \
  --entry-point=handleAction \
  --trigger-http \
  --allow-unauthenticated \
  --memory=512Mi \
  --timeout=60s \
  --set-secrets="API_SECRET_TOKEN=api-secret-token:latest"

4 Jebakan Umum

JebakanMasalahSolusi
Cold StartLatensi 2–5 detik saat instance tidak aktif--min-instances=1 untuk fungsi kritis
Batas TimeoutMaksimum 9 menit (540 detik)Bagi tugas besar melalui Pub/Sub
Izin Secret ManagerPermission denied saat runtimeBerikan peran secretmanager.secretAccessor
Kekurangan MemoriOOM saat pemrosesan beratSet --memory=2Gi --cpu=2

Ringkasan

TriggerKasus PenggunaanPertimbangan Utama
HTTPWebhook, endpoint APIAutentikasi, CORS
Pub/SubPemrosesan event asinkronDekoding base64, desain retry
FirestoreBereaksi terhadap perubahan dataHindari infinite loop
Cloud SchedulerBatch job terjadwalValidasi OIDC, zona waktu

Artikel Terkait

#claude-code #gcp #cloud-functions #typescript #serverless #pubsub
Gratis

PDF Gratis: Cheatsheet Claude Code dalam 5 Menit

Cukup masukkan emailmu dan kami akan langsung mengirim cheatsheet PDF A4 satu halaman.

Kami menjaga data pribadimu dengan aman dan tidak pernah mengirim spam.

Tingkatkan alur kerja Claude Code kamu

50 template prompt yang sudah teruji, siap copy-paste ke Claude Code sekarang juga.

Masa

Tentang Penulis

Masa

Engineer yang aktif menggunakan Claude Code. Mengelola claudecode-lab.com, media teknologi 10 bahasa dengan lebih dari 2.000 halaman.