توابع Node.js نسل اول را به نسل دوم ارتقا دهید

برنامه‌هایی که در حال حاضر از توابع نسل اول استفاده می‌کنند، باید با استفاده از دستورالعمل‌های این راهنما، به نسل دوم مهاجرت کنند. توابع نسل دوم از Cloud Run برای ارائه عملکرد بهتر، پیکربندی بهتر، نظارت بهتر و موارد دیگر استفاده می کنند.

مثال‌های موجود در این صفحه فرض می‌کنند که از جاوا اسکریپت با ماژول‌های CommonJS استفاده می‌کنید ( require وارد کردن سبک است)، اما همان اصول برای جاوا اسکریپت با ESM ( import … from واردات سبک) و TypeScript اعمال می‌شود.

فرآیند مهاجرت

توابع نسل اول و نسل دوم می توانند در کنار هم در یک فایل وجود داشته باشند. این اجازه می دهد تا تکه تکه به راحتی مهاجرت کنید، زیرا شما آماده هستید. توصیه می‌کنیم یک تابع را در یک زمان انتقال دهید، قبل از ادامه، آزمایش و تأیید را انجام دهید.

نسخه های Firebase CLI و firebase-function را تأیید کنید

مطمئن شوید که حداقل از Firebase CLI نسخه 12.00 و firebase-functions نسخه 4.3.0 استفاده می کنید. هر نسخه جدیدتر از نسل دوم و همچنین نسل اول پشتیبانی می کند.

واردات را به روز کنید

توابع نسل دوم از زیر بسته v2 در SDK firebase-functions وارد می‌شوند. این مسیر واردات متفاوت تمام آن چیزی است که Firebase CLI برای تعیین اینکه آیا کد تابع شما را به عنوان یک تابع نسل 1 یا 2 استقرار دهد، نیاز دارد.

بسته فرعی v2 ماژولار است و توصیه می کنیم فقط ماژول خاصی را که نیاز دارید وارد کنید.

قبل از: نسل اول

const functions = require("firebase-functions/v1");

بعد از: نسل دوم

// explicitly import each trigger
const {onRequest} = require("firebase-functions/v2/https");
const {onDocumentCreated} = require("firebase-functions/v2/firestore");

تعاریف ماشه را به روز کنید

از آنجایی که نسل دوم SDK از واردات مدولار حمایت می کند، تعاریف ماشه را به روز کنید تا واردات تغییر یافته از مرحله قبل را منعکس کند.

آرگومان های ارسال شده به فراخوان برای برخی از محرک ها تغییر کرده است. در این مثال، توجه داشته باشید که آرگومان های مربوط به callback onDocumentCreated در یک شی event واحد ادغام شده اند. علاوه بر این، برخی از تریگرها دارای ویژگی های پیکربندی جدید مناسبی هستند، مانند گزینه cors ماشه onRequest .

قبل از: نسل اول

const functions = require("firebase-functions/v1");

exports.date = functions.https.onRequest((req, res) => {
  // ...
});

exports.uppercase = functions.firestore
  .document("my-collection/{docId}")
  .onCreate((change, context) => {
    // ...
  });

بعد از: نسل دوم

const {onRequest} = require("firebase-functions/v2/https");
const {onDocumentCreated} = require("firebase-functions/v2/firestore");

exports.date = onRequest({cors: true}, (req, res) => {
  // ...
});

exports.uppercase = onDocumentCreated("my-collection/{docId}", (event) => {
  /* ... */
});

از پیکربندی پارامتری استفاده کنید

توابع نسل دوم، پشتیبانی از functions.config را به نفع یک رابط امن‌تر برای تعریف پارامترهای پیکربندی به صورت اعلامی در پایگاه کد شما کاهش می‌دهند. با ماژول params جدید، CLI استقرار را مسدود می‌کند مگر اینکه همه پارامترها دارای یک مقدار معتبر باشند و اطمینان حاصل شود که یک تابع با پیکربندی از دست رفته اجرا نمی‌شود.

به زیر بسته params مهاجرت کنید

اگر از پیکربندی محیط با functions.config استفاده کرده اید، می توانید پیکربندی موجود خود را به پیکربندی پارامتری منتقل کنید.

قبل از: نسل اول

const functions = require("firebase-functions/v1");

exports.date = functions.https.onRequest((req, res) => {
  const date = new Date();
  const formattedDate =
date.toLocaleDateString(functions.config().dateformat);

  // ...
});

بعد از: نسل دوم

const {onRequest} = require("firebase-functions/v2/https");
const {defineString} = require("firebase-functions/params");

const dateFormat = defineString("DATE_FORMAT");

exports.date = onRequest((req, res) => {
  const date = new Date();
  const formattedDate = date.toLocaleDateString(dateFormat.value());

  // ...
});

مقادیر پارامتر را تنظیم کنید

اولین باری که استقرار می‌کنید، Firebase CLI همه مقادیر پارامترها را درخواست می‌کند و مقادیر را در یک فایل dotenv ذخیره می‌کند. برای صادر کردن مقادیر functions.config خود، firebase functions:config:export را اجرا کنید.

برای ایمنی بیشتر، می‌توانید انواع پارامترها و قوانین اعتبارسنجی را نیز مشخص کنید.

مورد خاص: کلیدهای API

ماژول params با Cloud Secret Manager ادغام می شود که کنترل دسترسی دقیق به مقادیر حساس مانند کلیدهای API را فراهم می کند. برای اطلاعات بیشتر به پارامترهای مخفی مراجعه کنید.

قبل از: نسل اول

const functions = require("firebase-functions/v1");

exports.getQuote = functions.https.onRequest(async (req, res) => {
  const quote = await fetchMotivationalQuote(functions.config().apiKey);
  // ...
});

بعد از: نسل دوم

const {onRequest} = require("firebase-functions/v2/https");
const {defineSecret} = require("firebase-functions/params");

// Define the secret parameter
const apiKey = defineSecret("API_KEY");

exports.getQuote = onRequest(
  // make the secret available to this function
  { secrets: [apiKey] },
  async (req, res) => {
    // retrieve the value of the secret
    const quote = await fetchMotivationalQuote(apiKey.value());
    // ...
  }
);

گزینه های زمان اجرا را تنظیم کنید

پیکربندی گزینه های زمان اجرا بین نسل 1 و 2 تغییر کرده است. نسل دوم همچنین قابلیت جدیدی را برای تنظیم گزینه‌ها برای همه عملکردها اضافه می‌کند.

قبل از: نسل اول

const functions = require("firebase-functions/v1");

exports.date = functions
  .runWith({
    // Keep 5 instances warm for this latency-critical function
    minInstances: 5,
  })
  // locate function closest to users
  .region("asia-northeast1")
  .https.onRequest((req, res) => {
    // ...
  });

exports.uppercase = functions
  // locate function closest to users and database
  .region("asia-northeast1")
  .firestore.document("my-collection/{docId}")
  .onCreate((change, context) => {
    // ...
  });

بعد از: نسل دوم

const {onRequest} = require("firebase-functions/v2/https");
const {onDocumentCreated} = require("firebase-functions/v2/firestore");
const {setGlobalOptions} = require("firebase-functions/v2");

// locate all functions closest to users
setGlobalOptions({ region: "asia-northeast1" });

exports.date = onRequest({
    // Keep 5 instances warm for this latency-critical function
    minInstances: 5,
  }, (req, res) => {
  // ...
});

exports.uppercase = onDocumentCreated("my-collection/{docId}", (event) => {
  /* ... */
});

از همزمانی استفاده کنید

مزیت قابل توجه توابع نسل دوم، توانایی یک نمونه تابع برای ارائه بیش از یک درخواست به طور همزمان است. این می تواند به طور چشمگیری تعداد شروع سرد تجربه شده توسط کاربران نهایی را کاهش دهد. به طور پیش فرض، همزمانی روی 80 تنظیم شده است، اما می توانید آن را روی هر مقداری از 1 تا 1000 تنظیم کنید:

const {onRequest} = require("firebase-functions/v2/https");

exports.date = onRequest({
    // set concurrency value
    concurrency: 500
  },
  (req, res) => {
    // ...
});

تنظیم همزمان می تواند عملکرد را بهبود بخشد و هزینه عملکردها را کاهش دهد. درباره همزمانی در اجازه دادن به درخواست‌های همزمان بیشتر بیاموزید.

حسابرسی استفاده از متغیر جهانی

توابع نسل اول که بدون همزمانی در ذهن نوشته شده اند ممکن است از متغیرهای سراسری استفاده کنند که در هر درخواست تنظیم و خوانده می شوند. هنگامی که همزمانی فعال است و یک نمونه واحد شروع به رسیدگی به چندین درخواست به طور همزمان می کند، این ممکن است اشکالاتی را در عملکرد شما ایجاد کند زیرا درخواست های همزمان شروع به تنظیم و خواندن متغیرهای سراسری به طور همزمان می کنند.

در حین ارتقا، می توانید CPU تابع خود را روی gcf_gen1 تنظیم کنید و concurrency روی 1 تنظیم کنید تا رفتار نسل اول را بازیابی کنید:

const {onRequest} = require("firebase-functions/v2/https");

exports.date = onRequest({
    // TEMPORARY FIX: remove concurrency
    cpu: "gcf_gen1",
    concurrency: 1
  },
  (req, res) => {
    // ...
});

با این حال، این به عنوان یک راه حل طولانی مدت توصیه نمی شود، زیرا مزایای عملکرد عملکردهای نسل دوم را از دست می دهد. درعوض، استفاده از متغیرهای سراسری را در توابع خود حسابرسی کنید و وقتی آماده شدید، این تنظیمات موقت را حذف کنید.

ترافیک را به توابع جدید نسل دوم منتقل کنید

همانطور که هنگام تغییر منطقه یا نوع ماشه یک تابع ، باید به تابع نسل دوم یک نام جدید بدهید و به آرامی ترافیک را به آن منتقل کنید.

امکان ارتقاء یک تابع از نسل اول به نسل دوم با همین نام و اجرای firebase deploy وجود ندارد. انجام این کار منجر به خطا می شود:

Upgrading from GCFv1 to GCFv2 is not yet supported. Please delete your old function or wait for this feature to be ready.

قبل از اینکه این مراحل را دنبال کنید، ابتدا مطمئن شوید که عملکرد شما بی قدرت است، زیرا هم نسخه جدید و هم نسخه قدیمی عملکرد شما همزمان در طول تغییر اجرا می شوند. به عنوان مثال، اگر یک تابع نسل اول دارید که به نوشتن رویدادها در Firestore پاسخ می دهد، مطمئن شوید که پاسخ دادن به یک نوشتن دو بار، یک بار توسط تابع نسل 1 و یک بار توسط تابع نسل 2، در پاسخ به آن رویدادها برنامه شما را در یک حالت سازگار

  1. نام تابع را در کد توابع خود تغییر دهید. برای مثال، نام resizeImage به resizeImageSecondGen تغییر دهید.
  2. تابع را اجرا کنید، به طوری که هم تابع نسل اول و هم تابع نسل دوم در حال اجرا باشند.
    1. در مورد محرک‌های قابل فراخوانی، Task Queue و HTTP، با به‌روزرسانی کد کلاینت با نام یا URL تابع نسل دوم، شروع به اشاره همه کلاینت‌ها به تابع نسل دوم کنید.
    2. با محرک‌های پس‌زمینه، هر دو تابع نسل اول و نسل دوم بلافاصله پس از استقرار به هر رویداد پاسخ می‌دهند.
  3. وقتی تمام ترافیک خاموش شد، تابع نسل اول را با استفاده از فرمان firebase functions:delete firebase CLI حذف کنید.
    1. در صورت تمایل، نام تابع نسل 2 را برای مطابقت با نام تابع نسل 1 تغییر دهید.