เตรียม Firebase Extensions สำหรับการย้ายข้อมูลไปยัง Cloud Functions

คู่มือนี้จะแสดงวิธีย้ายข้อมูลส่วนขยายจากสภาพแวดล้อม Firebase Extensions ที่เลิกใช้งานแล้วไปยังฟังก์ชันที่ผู้ใช้ติดตั้งและทำให้ใช้งานได้ใน Cloud Functions ของตนเองสำหรับฐานของโค้ด Firebase (รุ่นที่ 2)

นี่คือเส้นทางการย้ายข้อมูลที่แนะนำ Firebase จะดูแลรายการ ส่วนขยายที่มีแพ็กเกจ npm อย่างเป็นทางการที่เทียบเท่ากัน โดยคู่มือนี้จะแนะนำขั้นตอน การสร้างส่วนขยายของคุณ

ในคู่มือนี้ เราจะใช้ส่วนขยายสตรีม Firestore ไปยัง BigQuery (firestore-bigquery-export) เป็นตัวอย่าง แต่ละส่วนจะจบลงด้วยตัวอย่างที่ใช้งานได้จริงซึ่งแสดงลักษณะของส่วนขยายก่อนการย้ายข้อมูลและลักษณะของส่วนขยายหลังการย้ายข้อมูลในรูปแบบแพ็กเกจ @firebase/firestore-bigquery-export

ลงชื่อสมัครใช้เพื่อรับข้อมูลเพิ่มเติมและความช่วยเหลือเกี่ยวกับการย้ายข้อมูลส่วนขยาย

หากมีคำถามเกี่ยวกับวิธีเปลี่ยนข้อมูลจาก Firebase Extensions คุณสามารถ ติดต่อเราได้ที่ firebase-extensions-migrator-support-external@google.com นอกจากนี้ เราจะส่งอีเมลถึงกลุ่มนี้เมื่ออัปเดตคำแนะนำพร้อมข้อมูลเพิ่มเติมเกี่ยวกับ การแพ็กเกจ การทดสอบ และการเผยแพร่ฟังก์ชันรุ่นที่ 2

หากต้องการเข้าร่วมกลุ่มนี้ ให้ส่งข้อความไปที่ firebase-extensions-migrator-support-external+subscribe@google.com ซึ่งจะตอบกลับด้วยอีเมลคำขอเป็นสมาชิก คุณต้องตอบกลับอีเมลนั้น ไม่ใช่คลิกปุ่ม "เข้าร่วมกลุ่มนี้"

ก่อนเริ่มต้น

หากต้องการย้ายข้อมูลให้เสร็จสมบูรณ์ คุณจะต้องใช้ฟีเจอร์ต่อไปนี้ของ Cloud Functions

  • การกำหนดค่าแบบพารามิเตอร์ พารามิเตอร์แต่ละรายการที่คุณประกาศใน extension.yaml จะกลายเป็นพารามิเตอร์ที่กำหนด ในโค้ดแพ็กเกจ

  • บทบาท IAM ที่ประกาศและ API ที่จำเป็น แต่ละบทบาทที่คุณประกาศใน extension.yaml จะกลายเป็นการเรียก requiresRole(...) และ API แต่ละรายการจะกลายเป็นการเรียก requiresAPI(...) ในโค้ดฟังก์ชัน ในเวลาที่ทำการติดตั้งใช้งาน Firebase CLI จะให้บทบาทที่ประกาศไว้แก่บัญชีบริการรันไทม์ที่มีการจัดการ และเปิดใช้ API ที่ประกาศไว้ในนามของคุณ

  • เหตุการณ์วงจรสำหรับCloud Functionsโค้ดเบส Cloud Functions ตอนนี้โค้ดเบสรองรับเหตุการณ์วงจรที่คล้ายกับ Firebase Extensions แล้ว ประกาศการตั้งค่าเวลาติดตั้งและเวลาอัปเดตด้วย Hook วงจรของแอป afterFirstDeploy(...) และ afterRedeploy(...) ซึ่งจะแทนที่ lifecycleEvents ที่คุณประกาศใน extension.yaml

จัดทำรายการส่วนขยาย

เริ่มต้นด้วยการทำรายการส่วนขยายของคุณ ซึ่งเป็นรายการทั้งหมด ที่ส่วนขยายประกาศ จัดส่ง และจัดทำเอกสาร เพื่อให้ทุกลักษณะการทำงานมี ปลายทางที่กำหนดไว้ในฟังก์ชันรุ่นที่ 2 และไม่มีข้อมูลใดสูญหายใน การย้ายข้อมูล

ตรวจสอบแต่ละรายการต่อไปนี้และจดบันทึกสิ่งที่คุณพบ

  • extension.yaml ซึ่งประกาศพารามิเตอร์ ฟังก์ชัน เหตุการณ์ บทบาท IAM, API ที่จำเป็น, Secret และฮุควงจร

  • functions/ ซึ่งมีโค้ดฟังก์ชัน ทรัพยากร Dependency การกำหนดค่าบิลด์ ทริกเกอร์ และฟังก์ชันคิวงาน

  • README.md, PREINSTALL.md และ POSTINSTALL.md ซึ่งมีขั้นตอนการตั้งค่า คำเตือน และหมายเหตุการเรียกเก็บเงิน

  • scripts/ ซึ่งมีเครื่องมือสำหรับการนำเข้า การแสดงโฆษณาสำรอง IAM การซ่อม หรือการย้ายข้อมูล และเครื่องมืออื่นๆ ที่คุณจัดส่งพร้อมกับส่วนขยาย

จากนั้นสำหรับแต่ละรายการใน extension.yaml ให้ตัดสินใจว่าจะวางรายการนั้นไว้ที่ใดในแพ็กเกจ npm

  • แปลงการกำหนดค่าผู้ใช้เป็นพารามิเตอร์ Cloud Functions (ส่วนที่ 5)

  • แปลงข้อมูลลับเป็น Cloud Functions secrets (ส่วน 6)

  • แปลงบทบาท IAM เป็นrequiresRole(...)ประกาศ (ส่วนที่ 8)

  • แปลง Google API ที่จำเป็นเป็นrequiresAPI(...)ประกาศตามความเหมาะสม (ส่วนที่ 8)

  • แปลง Hook การติดตั้งและการอัปเดตเป็นการประกาศ afterFirstDeploy(...) และ afterRedeploy(...) (ส่วนที่ 8)

ตัวอย่างการทำงาน: สตรีม Firestore ไปยัง BigQuery

การอ่าน firestore-bigquery-export/extension.yaml และฟังก์ชันจะสร้างข้อมูลต่อไปนี้

ใน extension.yaml จำนวน / มูลค่า ตำแหน่งที่ข้อมูลจะไป
พารามิเตอร์ 25 (COLLECTION_PATH, DATASET_ID, TABLE_ID, DATASET_LOCATION, VIEW_TYPE, …) Cloud Functions params (section 5)
API bigquery.googleapis.com requiresAPI(...) (ส่วนที่ 7)
บทบาท bigquery.dataEditor, datastore.user, bigquery.user requiresRole(...) (ส่วนที่ 7)
ทรัพยากร ทริกเกอร์เหตุการณ์ 1 รายการ (fsexportbigquery) + ฟังก์ชันคิวงาน (initBigQuerySync, setupBigQuerySync) ฟังก์ชันของแพ็กเกจที่ส่งออก (ส่วนที่ 3)
lifecycleEvents onInstall → initBigQuerySync; onUpdate / onConfigure → setupBigQuerySync afterFirstDeploy / afterRedeploy (ส่วนที่ 9)
scripts/ import/ (backfill), gen-schema-view/ เก็บไว้เป็นสคริปต์ (อยู่นอกขอบเขตที่นี่)

ส่วนขยายไม่ได้ประกาศประเภทพารามิเตอร์ลับ ดังนั้นจึงไม่มีอะไรที่จะย้ายข้อมูลในส่วนที่ 6 ของคำแนะนำนี้ ทริกเกอร์เหตุการณ์เป็นรุ่นที่ 2 อยู่แล้ว มีเพียงฟังก์ชันคิว งานเท่านั้นที่ยังเป็นรุ่นที่ 1 (เกี่ยวข้องในส่วนที่ 3)

อัปเดต package.json

อัปเดตไฟล์ package.json ของส่วนขยาย หากคุณย้ายข้อมูลส่วนขยายเดียว นี่อาจเป็นรูท package.json หากคุณย้ายข้อมูลส่วนขยายจำนวนมากในที่เก็บเดียว ให้สร้างแพ็กเกจของแต่ละส่วนขยาย

เวอร์ชัน SDK ขั้นต่ำ ประกาศ firebase-functions >= 7.3 และ firebase-admin >= 14.2.0 เป็นทรัพยากร Dependency ประกาศเวอร์ชัน firebase-functions เป็นการขึ้นต่อกันแบบเพียร์ด้วย

{
  "name": "<package-name>",
  "version": "1.0.0",
  "main": "lib/index.js",
  "types": "lib/index.d.ts",
  "exports": {
    ".": {
      "types": "./lib/index.d.ts",
      "default": "./lib/index.js"
    }
  },
  "engines": {
    "node": ">=22"
  },
  "peerDependencies": {
    "firebase-functions": "^7.3.0"
  },
  "dependencies": {
    "firebase-functions": "^7.3.0",
    "firebase-admin": "^14.2.0"
  }
}

ประกาศ firebase-functions เป็นทรัพยากร Dependency แบบเพียร์นอกเหนือจากทรัพยากร Dependency ปกติ เพื่อให้โปรเจ็กต์ Cloud Functions ของผู้ใช้มี SDK เวอร์ชันเดียวกับที่ใช้เขียนไลบรารีของคุณ

ตัวอย่างการทำงาน: สตรีม Firestore ไปยัง BigQuery

ก่อน ฟังก์ชัน/package.json ของส่วนขยายเป็นแบบส่วนตัว โดยจะตั้งชื่อ รหัสส่วนขยาย และประกาศ firebase-functions เป็นการขึ้นต่อกันโดยตรง

{
  "name": "firestore-bigquery-export",
  "main": "lib/index.js",
  "private": true,
  "dependencies": {
    "@firebaseextensions/firestore-bigquery-change-tracker": "^2.0.4",
    "firebase-admin": "^14.2.0",
    "firebase-functions": "^6.3.2"
  }
}

หลังจากนั้น แพ็กเกจที่เผยแพร่ได้: ชื่อที่กำหนดขอบเขต แผนที่การส่งออก และ firebase-functions ย้ายไปที่ peerDependencies:

{
  "name": "@firebase/firestore-bigquery-export",
  "version": "0.1.0",
  "main": "lib/index.js",
  "types": "lib/index.d.ts",
  "exports": {
    ".":     { "types": "./lib/index.d.ts", "default": "./lib/index.js" },  },
  "engines": { "node": ">=22" },
  "peerDependencies": { "firebase-functions": "^7.3.0" },
  "dependencies": {
      "@firebaseextensions/firestore-bigquery-change-tracker": "^2.0.4",
      "firebase-admin": "^14.2.0",
      "firebase-functions": "^7.3.0"
    }
}

อัปเกรดฟังก์ชันจากรุ่นที่ 1 เป็นรุ่นที่ 2

หากส่วนขยายยังคงส่งออกฟังก์ชันรุ่นที่ 1 ให้แปลงฟังก์ชันแต่ละรายการเป็นฟังก์ชันรุ่นที่ 2 ที่เทียบเท่า นำเข้าจากโมดูล firebase-functions/... และส่งการตั้งค่ารันไทม์ในตัวเลือกฟังก์ชัน

คุณลดความพยายามในการเขียนใหม่ได้ด้วยการแยกโครงสร้างเหตุการณ์ที่แก้ไขแล้วรุ่นที่ 2 และหลีกเลี่ยงการเขียนตรรกะของฟังก์ชันใหม่ เนื่องจากตอนนี้ SDK รุ่นที่ 2 แสดงพารามิเตอร์ V1 เป็นฟิลด์ในออบเจ็กต์เหตุการณ์ ซึ่งช่วยให้คุณใช้พารามิเตอร์ที่แยกโครงสร้าง/ตั้งชื่อ และคงตรรกะทางธุรกิจไว้ได้โดยไม่มีการเปลี่ยนแปลง

ก่อน รุ่นที่ 1

import * as functions from "firebase-functions/v1";

export const sync = functions.firestore
  .document("{collectionId}/{documentId}")
  .onWrite(async (change, context) => {
    await handleWrite(change.before, change.after, context.params);
  });

หลังจากนั้น รุ่นที่ 2:

import { onDocumentWritten } from "firebase-functions/firestore";

export const syncV2 = onDocumentWritten(
  { document: "{collectionId}/{documentId}" },
  async ({change,context}) =>
    await handleWrite(change.before, change.after, context.params);
);

ดูรายการความแตกต่างทั้งหมดระหว่างฟังก์ชันรุ่นที่ 1 กับรุ่นที่ 2 ได้ที่Cloud Functionsการเปรียบเทียบเวอร์ชัน

แปลงพารามิเตอร์และข้อมูลลับของส่วนขยาย

พารามิเตอร์การแปลง

พารามิเตอร์แต่ละรายการที่คุณประกาศใน extension.yaml จะกลายเป็น Cloud Functions param

แปลงการอ่านสภาพแวดล้อมโดยตรง

const collectionPath = process.env.COLLECTION_PATH;

เป็นพารามิเตอร์ Cloud Functions

import { defineString } from "firebase-functions/params";
import { onDocumentWritten} from "firebase-functions/firestore";

const collectionPath = defineString("COLLECTION_PATH");

// Pass the param directly when used as a placeholder (e.g. trigger path)
export const sync = onDocumentWritten(
  { document: collectionPath },
  async (event) => {
    // Call .value() to read the string inside a handler
    const path = collectionPath.value();
    await handleWrite(path, event);
  }
);

ใช้ collectionPath.value() เพื่ออ่านสตริงภายในแฮนเดิล และใช้ collectionPath โดยตรงในตำแหน่งที่คาดว่าจะใช้ตัวยึดตำแหน่ง เช่น เส้นทางการทริกเกอร์ฟังก์ชัน

Firebase CLI จะค้นหาพารามิเตอร์และอ่านค่าจาก .env, .envprojectId หรือแจ้งให้ผู้ใช้ทราบระหว่างการติดตั้งใช้งาน ใช้ชื่อพารามิเตอร์เดิมเพื่อให้ค่าจากการติดตั้งที่มีอยู่ยังคงอยู่

คุณไม่ควรเปลี่ยนชื่อพารามิเตอร์ที่ประกาศไว้ในโค้ด โดยเด็ดขาด การย้ายข้อมูลส่วนขยายจะเก็บค่าพารามิเตอร์ของผู้ใช้ปลายทางที่มีอยู่ โดยอัตโนมัติ แต่จะทำได้ก็ต่อเมื่อชื่อไม่เปลี่ยนแปลง

ตัวอย่างการทำงาน: สตรีม Firestore ไปยัง BigQuery ก่อน พารามิเตอร์ที่ประกาศใน extension.yaml อ่านเป็นตัวแปรสภาพแวดล้อมดิบใน config.ts:

# extension.yaml
-   param: COLLECTION_PATH
  label: Collection path
  type: string
  required: true
// functions/src/config.ts
collectionPath: process.env.COLLECTION_PATH,

หลังจากนั้น defineString รายการเดียว CLI จะค้นพบและอ่านจาก .env

// src/config.ts
import { defineString } from "firebase-functions/params";

collectionPath: defineString("COLLECTION_PATH", {
  label: "Collection path",
  // We now support "nonEmpty: true" to ensure a value other than the empty string
  // is entered, analagous to "required: true" in extensions.yaml
  input: { text: { nonEmpty: true} }
}),

ชื่อพารามิเตอร์จะยังคงเหมือนเดิม ดังนั้นไฟล์ .env ที่มีอยู่จะยังคงทำงานได้

แปลงข้อมูลลับ

ใน extension.yaml คุณจะประกาศข้อมูลลับด้วย type: secret รันไทม์ของส่วนขยาย จะจัดเก็บและเชื่อมโยงตัวแปรเหล่านี้เพื่อให้โค้ดส่วนขยายอ่าน process.env.PARAM_NAME ได้โดยตรง ในCloud Functionsฐานของโค้ดทั่วไป คุณจะประกาศและเชื่อมโยงแต่ละ Secret อย่างชัดเจน

import { defineSecret } from "firebase-functions/params";
import { onRequest } from "firebase-functions/https";

const apiKey = defineSecret("API_KEY");
export const fn = onRequest({ secrets: [apiKey] }, handler);

เมื่อย้ายข้อมูลส่วนขยายไปยังแพ็กเกจ/ชุดเครื่องมือ npm แล้ว ระบบจะจัดการการอ้างอิงลับในไฟล์ .env ของผู้ใช้ปลายทาง คุณไม่ควรเปลี่ยนชื่อลับที่ประกาศไว้ในโค้ดโดยเด็ดขาด ในระหว่างการย้ายข้อมูล ระบบจะย้ายข้อมูลลับของผู้ใช้ปลายทางตามนั้น

ตัวอย่างการทำงาน: อีเมลทริกเกอร์จาก Cloud Firestore

ก่อน MAIL_COLLECTION และ SMTP_PASSWORD จะอ่านเป็นตัวแปรสภาพแวดล้อมดิบใน config.ts ดังนี้

# extension.yaml
-   param: MAIL_COLLECTION
  label: Email documents collection
  type: string
  default: mail
  required: true

-   param: SMTP_PASSWORD
  label: SMTP password
  type: secret
// functions/src/config.ts
mailCollection: process.env.MAIL_COLLECTION,
smtpPassword: process.env.SMTP_PASSWORD,

หลังจากนั้น defineString 1 รายการและ defineSecret 1 รายการ CLI จะค้นพบทั้ง 2 รายการ และอ่านจาก .env

import { defineString, defineSecret } from "firebase-functions/params";
import { onDocumentWritten } from "firebase-functions/firestore";

const mailCollection = defineString("MAIL_COLLECTION",{ label: "Email documents collection",
 default: "mail"
});

const smtpPassword = defineSecret("SMTP_PASSWORD", { label: "SMTP password" });

export const processQueue = onDocumentWritten(
  { document: `${mailCollection}/{documentId}`, secrets: [smtpPassword] },
  async (event) => {
    const collection = mailCollection.value();
    const password = smtpPassword.value();
    // ...
  }
);

ย้ายข้อมูลการเรียกคิวงานภายใน

ส่วนขยายบางรายการจะจัดคิวงานลงในคิวงานของตัวเองจากภายในโค้ดฟังก์ชันโดยใช้ Firebase Admin SDK ซึ่งแตกต่างจากการรับงานที่ส่ง (ครอบคลุมในส่วนอัปเกรดฟังก์ชันและแปลง ฮุกวงจร) ในที่นี้ รหัสของคุณคือผู้ผลิตที่เรียกใช้ queue.enqueue(...)

Admin SDK เวอร์ชันก่อนหน้ากำหนดให้ส่วนขยายต้องส่งรหัสอินสแตนซ์ของส่วนขยายของตนเองเป็นพารามิเตอร์ที่ 2 เพื่อกำหนดเป้าหมายฟังก์ชัน Task Queue ในส่วนขยายเดียวกัน ตั้งแต่ `firebase-admin` 14.2.0 เป็นต้นไป คุณไม่จำเป็นต้องดำเนินการนี้และเราไม่แนะนำให้ทำ ตอนนี้ Task Queue API จะกำหนดเป้าหมายเป็นคิวของงานในบริบทเดียวกัน (เช่น ส่วนขยาย) โดยค่าเริ่มต้น เราขอแนะนำให้คุณนำพารามิเตอร์นี้ออกจากโค้ดทั้งในรูปแบบส่วนขยายและฟังก์ชันแบบสแตนด์อโลน การนำพารามิเตอร์นี้ออกจะช่วยให้มั่นใจได้ถึงความสามารถในการพกพาและความเข้ากันได้ในอนาคต

ส่วนอื่นๆ ทั้งหมดเกี่ยวกับการเรียก enqueue ไม่ว่าจะเป็นเส้นทางทรัพยากร locations/region/functions/name เพย์โหลดของงาน และตรรกะการลองใหม่จะยังคงเหมือนเดิม

ดูรายละเอียดเพิ่มเติมเกี่ยวกับการจัดคิวฟังก์ชันด้วย Cloud Tasks ได้ที่ /docs/functions/task-functions

ก่อน ส่วนขยายรุ่นที่ 1

import { getFunctions } from "firebase-admin/functions";

const queue = getFunctions().taskQueue(
  `locations/${config.location}/functions/syncBigQuery`,
  process.env.EXT_INSTANCE_ID, // extension instance ID, injected by the runtime
);
await queue.enqueue(taskData);

หลังจากนั้น ส่วนขยายรุ่นที่ 2

import { getFunctions } from "firebase-admin/functions";

const queue = getFunctions().taskQueue(
  `locations/${process.env.FUNCTION_REGION}/functions/syncBigQuery`);
await queue.enqueue(taskData);

หากการเรียก enqueue มุ่งเป้าไปที่ฐานของโค้ดที่มีคำนำหน้า ชื่อฟังก์ชันที่ค้นพบ จะมีคำนำหน้าด้วย (เช่น orders-syncBigQuery)

ประกาศ API และบทบาท IAM ที่จำเป็น

ย้ายข้อกำหนด IAM และ API ของส่วนขยายออกจาก extension.yaml ไปยัง code:

import { requiresAPI, requiresRole } from "firebase-functions"

requiresAPI("bigquery.googleapis.com", "Needed to write changelog rows");
requiresRole("roles/bigquery.dataEditor");
requiresRole("roles/bigquery.user");

เมื่อใช้การรักษาความปลอดภัยแบบประกาศ Firebase CLI จะสร้างหรืออัปเดตบัญชีบริการรันไทม์ที่มีการจัดการสำหรับฐานของโค้ด และให้สิทธิ์แก่บัญชีดังกล่าวในการรวมบทบาทที่ประกาศทั้งหมด จัดทำเอกสารสำหรับผู้ใช้ว่าฟังก์ชันทั้งหมดในฐานของโค้ดทำงาน ด้วยบทบาทเหล่านั้น เว้นแต่ API สุดท้ายจะรองรับโมเดลที่แคบกว่า

ตัวอย่างการทำงาน: สตรีม Firestore ไปยัง BigQuery

ก่อน ประกาศใน extension.yaml โดยรันไทม์ของส่วนขยายจะเปิดใช้ API และมอบบทบาทให้กับบัญชีที่จัดการ

apis:
  -   apiName: bigquery.googleapis.com
roles:
  -   role: bigquery.dataEditor
  -   role: datastore.user
  -   role: bigquery.user

หลังจากนั้น ประกาศในโค้ดด้วย requiresAPI และ requiresRole ดังนี้

import { requiresAPI, requiresRole } from "firebase-functions/";
requiresAPI("bigquery.googleapis.com",
  "Needed to write changelog rows and views");
requiresRole("roles/biguqery.dataEditor");
requiresRole("roles/datastore.user");
requiresRole("roles/bigquery.user");

แปลงฮุกวงจรลูกค้า

หากส่วนขยายเรียกใช้ getExtensions().runtime() เช่น setProcessingState หรือ setFatalError ให้ลบการเรียกเหล่านั้น เนื่องจากจะทำให้เกิดข้อผิดพลาดหากเรียกใช้จากฟังก์ชันรุ่นที่ 2 ที่โดยปกติแล้วจะมีการติดตั้งใช้งาน afterFirstDeploy และ afterRedeploy เป็นตัวกำหนดสถานะวงจรในตอนนี้ ในกรณีที่ไม่ได้ใช้การติดตามสถานะนี้

Firebase Extensions สามารถเรียกใช้การตั้งค่าเมื่อผู้ใช้ติดตั้ง อัปเดต หรือ กำหนดค่าส่วนขยายใหม่ ในแพ็กเกจ npm ให้ประกาศการดำเนินการวงจรที่เทียบเท่า ในโค้ด

สำหรับการตั้งค่าครั้งเดียว ให้ทำดังนี้

import { afterFirstDeploy } from "firebase-functions/lifecycle";
import { onTaskDispatched } from "firebase-functions/tasks";

export const runInitialSetup = onTaskDispatched(async (request) => {
  await initializeResources(request.data);
});

afterFirstDeploy({
  task: {
    function: "runInitialSetup",
    body: {}
  }
});

สำหรับการอัปเดตการกำหนดค่าหรือโค้ด ให้ทำดังนี้

import { afterRedeploy } from "firebase-functions/lifecycle";

afterRedeploy({
  task: {
    function: "runInitialSetup",
    body: { reconcile: true }
  }
});

ทำให้การดำเนินการวงจรลูกค้าเป็นแบบ Idempotent ผู้ใช้อาจต้องเรียกใช้คำสั่งอีกครั้งด้วยตนเองหากการส่งหรือการดำเนินการล้มเหลว

firebase functions:lifecycle:run afterFirstDeploy CODEBASE_NAME
firebase functions:lifecycle:run afterRedeploy CODEBASE_NAME

ตัวอย่างการทำงาน: สตรีม Firestore ไปยัง BigQuery

ก่อน lifecycleEvents ใน extension.yaml ซึ่งขับเคลื่อนโดยรันไทม์ของส่วนขยาย

lifecycleEvents:
  onInstall:
    function: initBigQuerySync
    processingMessage: Configuring BigQuery Sync.
  onUpdate:
    function: setupBigQuerySync
    processingMessage: Configuring BigQuery Sync
  onConfigure:
    function: setupBigQuerySync
    processingMessage: Configuring BigQuery Sync

หลังจากนั้น ประกาศในโค้ด โดยการจัดสรรงาน BigQuery ในการ ติดตั้งใช้งานครั้งแรก

import { afterFirstDeploy, afterRedeploy } from "firebase-functions/lifecycle";

afterFirstDeploy({ task: { function: "initBigQuerySync" } });
afterRedeploy({ task: { function: "setupBigQuerySync" } });

การจัดสรรเป็นแบบ Idempotent ดังนั้นการเรียกใช้ซ้ำจะทำให้ชุดข้อมูล ตาราง และมุมมองสอดคล้องกัน ผู้ใช้สามารถเรียกใช้ด้วยตนเองอีกครั้งได้ด้วย firebase functions:lifecycle:run afterFirstDeploy CODEBASE_NAME

การตั้งค่าเอกสารสำหรับผู้ใช้

  • เขียนREADMEแพ็กเกจที่อธิบายข้อมูลต่อไปนี้เป็นอย่างน้อย

  • ค่า .env ที่แพ็กเกจต้องการ

  • ข้อมูลลับที่แพ็กเกจต้องการและวิธีย้ายข้อมูลลับที่มีอยู่

  • บทบาท IAM ที่แพ็กเกจประกาศด้วย requiresRole(...)

  • Google API ที่แพ็กเกจเปิดใช้หรือต้องใช้

  • Hook วงจรการใช้งานที่แพ็กเกจประกาศและวิธีเรียกใช้ซ้ำด้วยตนเอง

  • หมายเหตุเกี่ยวกับการเรียกเก็บเงิน

  • มีการเปลี่ยนแปลงอะไรบ้างเมื่อเทียบกับส่วนขยายเดิม

ตัวอย่างการทำงาน: สตรีม Firestore ไปยัง BigQuery

README ของแพ็กเกจจะแสดงตาราง "สิ่งที่เปลี่ยนแปลง" ที่ชัดเจน

ข้อกังวล เป็นส่วนขยาย เป็น @firebase/firestore-bigquery-export
การกำหนดค่า พารามิเตอร์ส่วนขยาย พารามิเตอร์ของฟังก์ชันผ่าน .env
IAM ได้รับจากส่วนขยาย requiresRole(...) ใช้เมื่อติดตั้งใช้งาน
การจัดสรร งานวงจรลูกค้าตามส่วนขยาย งาน afterFirstDeploy / afterRedeploy
ชื่อฟังก์ชัน ext-instanceId-fsexportbigquery fsexportbigquery (มีคำนำหน้าหรือไม่ก็ได้)

ทดสอบฟังก์ชันรุ่นที่ 2

ตอนนี้คุณควรมีฟังก์ชันรุ่นที่ 2 ซึ่งเมื่อนำไปใช้งานแล้วจะทำงาน เหมือนกับการติดตั้งส่วนขยายใหม่ทุกประการ ขั้นตอนสุดท้ายคือการยืนยัน และแก้ไขปัญหาที่เกิดขึ้นโดยไม่ตั้งใจระหว่างทาง

ตรวจสอบว่าคุณใช้ firebase-tools >= 15.25.1 และทําการติดตั้งใช้งานฟังก์ชันรุ่นที่ 2 ที่แปลงแล้วในโปรเจ็กต์ทดสอบ พร้อมทรัพยากรที่เหมาะสมเพื่อทดสอบลักษณะการทํางาน หากคุณมีโปรเจ็กต์ทดสอบที่ตั้งค่าไว้แล้วจากการทดสอบส่วนขยาย ให้ใช้คำสั่งต่อไปนี้

firebase deploy --only functions

หลังจากป้อนคำสั่งนี้ ให้กรอกวิซาร์ดที่ปรากฏขึ้นซึ่งจะแจ้งให้คุณป้อนค่าพารามิเตอร์ในลักษณะเดียวกับที่คุณกรอกแบบฟอร์มการติดตั้งในคอนโซล Firebase สำหรับส่วนขยาย

ตัวอย่างการทำงาน: สตรีม Firestore ไปยัง BigQuery

เราจะยืนยันการซิงค์Cloud FirestoreกับBigQueryตั้งแต่ต้นทางถึงปลายทางดังนี้

  1. ในCloud Firestoreคอนโซล ให้สร้างคอลเล็กชันที่คุณตั้งค่าเป็น COLLECTION_PATH (users) หากยังไม่มี
  2. สร้างเอกสารชื่อ bigquery-mirror-test ที่มีฟิลด์ที่มีค่าใดก็ได้
  3. ในBigQueryคอนโซล ให้ค้นหาตารางบันทึกการเปลี่ยนแปลงดิบ โดยควรมีแถวเดียวที่บันทึกการสร้างเอกสาร ดังนี้
SELECT * FROM `PROJECT_ID.analytics.users_raw_changelog`
  1. ค้นหามุมมองล่าสุด ซึ่งควรแสดงเหตุการณ์การเปลี่ยนแปลงล่าสุดสำหรับ เอกสารเดียวที่มีอยู่: bigquery-mirror-test
SELECT * FROM `PROJECT_ID.analytics.users_raw_latest`
  1. ลบเอกสาร bigquery-mirror-test ใน Cloud Firestore โดยจะหายไปจากมุมมองล่าสุด และระบบจะต่อท้ายเหตุการณ์ DELETE เข้ากับตารางบันทึกการเปลี่ยนแปลงดิบ

คุณตรวจสอบประวัติทั้งหมดของเอกสารเดียวได้โดยทำดังนี้

SELECT *
   FROM `PROJECT_ID.analytics.users_raw_changelog`
   WHERE document_name = "bigquery-mirror-test"
   ORDER BY timestamp ASC

ความแตกต่างจากการทดสอบส่วนขยาย

  • ทริกเกอร์จะทําการติดตั้งใช้งานเป็น fsexportbigquery (อาจมีคำนำหน้าเป็นฐานของโค้ด) ไม่ใช่ ext-&lt;instanceId&gt;-fsexportbigquery มองหาชื่อนั้นใน Cloud Functions แดชบอร์ดและบันทึก
  • ตอนนี้โค้ดจะทำงานใน Firebase Local Emulator Suite เหมือนฟังก์ชันปกติ คุณสามารถตั้งค่าพารามิเตอร์เพื่อใช้ในโปรแกรมจำลองด้วย .env.local นอกจากนี้ คุณยังทำ Unit Test โค้ดได้โดยใช้ SDK firebase-functions-test ตามที่อธิบายไว้ในการทำ Unit Test ของ Cloud Functions
  • การจัดสรรไม่ได้ขับเคลื่อนโดยรันไทม์ของส่วนขยายอีกต่อไป หากตารางบันทึกการเปลี่ยนแปลง หายไปหลังจากที่ติดตั้งใช้งาน ให้เรียกใช้การตั้งค่าอีกครั้งด้วยตนเอง: firebase functions:lifecycle:run afterFirstDeploy CODEBASE_NAME งานนี้เป็น ไอดีมโปเตนต์ ดังนั้นการเรียกใช้ซ้ำจะทำให้ชุดข้อมูล ตาราง และมุมมองสอดคล้องกัน
  • ค่าพารามิเตอร์มาจาก .env ไม่ใช่แบบฟอร์มการติดตั้ง ดังนั้นการเรียกใช้ซ้ำ ของ firebase deploy จะไม่ใช่แบบอินเทอร์แอกทีฟเมื่อ .env เสร็จสมบูรณ์