امتحان مجدد توابع ناهمزمان

این سند توضیح می‌دهد که چگونه می‌توانید درخواست کنید تا عملکردهای پس‌زمینه‌ای ناهم‌زمان (غیرHTTPS) درصورت عدم موفقیت دوباره امتحان شوند.

چرا توابع رویدادمحور تکمیل نمی‌شوند

در موارد نادر، ممکن است تابعی به‌دلیل خطای داخلی زودتر از موعد خارج شود، و به‌طور پیش‌فرض ممکن است تابع به‌طور خودکار دوباره امتحان شود یا نشود.

به‌طور معمول‌تر، یک تابع رویدادمحور ممکن است به‌دلیل خطاهای ایجادشده در کد تابع، با موفقیت تکمیل نشود. دلایل احتمالی این اتفاق عبارت‌اند از:

  • تابع حاوی اشکال است و زمان اجرا استثنایی را ایجاد می‌کند.
  • تابع نمی‌تواند به نقطه پایانی سرویس دسترسی پیدا کند، یا هنگام تلاش برای انجام این کار، مهلت آن تمام می‌شود.
  • تابع به‌طور عمدی استثنایی را ایجاد می‌کند (برای مثال، زمانی که یک پارامتر اعتبارسنجی را انجام نمی‌دهد).
  • تابع Node.js وعده ردشده‌ای را برمی‌گرداند یا مقدار غیرnull را به فراخوانی برمی‌گرداند.

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

معناشناسی امتحان مجدد

‫Cloud Functions اجرای حداقل یک‌باره تابع رویدادمحور را برای هر رویداد منتشرشده توسط منبع رویداد فراهم می‌کند. به‌طور پیش‌فرض، اگر فراخوانی تابع با خطا خاتمه یابد، تابع دوباره فراخوانی نمی‌شود و رویداد حذف می‌شود. وقتی تلاش مجدد را در یک تابع رویدادمحور فعال می‌کنید، Cloud Functions فراخوانی تابع ناموفق را تا زمانی که با موفقیت تکمیل شود یا پنجره تلاش مجدد منقضی شود، دوباره امتحان می‌کند.

وقتی تلاش‌های مجدد برای تابعی فعال نباشد (که حالت پیش‌فرض است)، تابع همیشه گزارش می‌کند که با موفقیت اجرا شده است و کدهای پاسخ 200 OK ممکن است در گزارش‌های آن ظاهر شود. این اتفاق حتی اگر تابع با خطا مواجه شود رخ می‌دهد. برای اینکه مشخص شود تابع شما چه زمانی با خطا مواجه می‌شود، حتماً خطاها را به‌درستی گزارش کنید.

پیکربندی کردن تلاش‌های مجدد از کد تابع

با Cloud Functions for Firebase، می‌توانید تلاش‌های مجدد را در کد برای یک تابع فعال کنید. برای انجام این کار برای رویداد پس‌زمینه‌ای مثل ایجاد سند جدید Firestore، گزینه خط‌مشی failurePolicy (نسل اول) یا retry (نسل دوم) را روی true تنظیم کنید:

نسل اول

exports.docCreated = functions
  .runWith({
    // retry on failure
    failurePolicy: true,
  })
  .firestore.document("my-collection/{docId}")
  .onCreate((change, context) => {
    /* ... */
  });

نسل دوم

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

exports.docCreated = onDocumentCreated(
  {
    // retry on failure
    retry: true,
  },
  "my-collection/{docId}",
  (event) => {
    /* ... */
  },
);

تنظیم true همان‌طور که نشان داده شده است تابعی را پیکربندی می‌کند تا درصورت عدم موفقیت دوباره تلاش کند.

پنجره تلاش مجدد

برای کارکردهای نسل دوم، این پنجره تلاش مجدد پس‌از ۲۴ ساعت منقضی می‌شود. برای عملکردهای نسل اول، پس‌از ۷ روز منقضی می‌شود. ‫Cloud Functions تابع رویدادمحور تازه‌ساخته‌شده را بااستفاده از استراتژی پس‌گیری نمایی، با پس‌گیری افزایشی بین ۱۰ و ۶۰۰ ثانیه، دوباره امتحان می‌کند. این خط‌مشی اولین‌بار که کارکردهای جدید را پیاده‌سازی می‌کنید اعمال می‌شود. این تغییرات به‌صورت عطف به‌ماسبق بر کارکردهای موجود که قبل‌از اعمال تغییرات شرح‌داده‌شده در این یادداشت انتشار مستقر شده‌اند اعمال نمی‌شود، حتی اگر کارکردها را مجدداً مستقر کنید.

روال‌های مطلوب

این بخش روال‌های مطلوب را برای استفاده از تلاش‌های مجدد شرح می‌دهد.

از تلاش مجدد برای مدیریت خطاهای موقت استفاده کنید

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

برای جلوگیری از حلقه‌های تلاش مجدد بی‌نهایت، شرط پایانی تنظیم کنید

بهترین روش این است که هنگام استفاده از تلاش‌های مجدد، از تابع خود دربرابر حلقه بی‌نهایت محافظت کنید. می‌توانید این کار را با افزودن یک شرط پایان به‌خوبی تعریف‌شده، قبل‌از شروع پردازش تابع انجام دهید. توجه داشته باشید که این تکنیک فقط درصورتی کار می‌کند که تابع شما با موفقیت شروع شود و بتواند وضعیت پایانی را ارزیابی کند.

رویکردی ساده اما مؤثر این است که رویدادهایی با مُهرهای زمان قدیمی‌تر از زمان مشخصی را دور بریزید. این کار کمک می‌کند تا درصورت تداوم خطاها یا طولانی‌تر بودن آن‌ها از حد انتظار، از اجرای بیش‌ازحد جلوگیری شود.

برای مثال، این تکه‌کد همه رویدادهای قدیمی‌تر از ۱۰ ثانیه را دور می‌اندازد:

const eventAgeMs = Date.now() - Date.parse(event.timestamp);
const eventMaxAgeMs = 10000;
if (eventAgeMs > eventMaxAgeMs) {
  console.log(`Dropping event ${event} with age[ms]: ${eventAgeMs}`);
  callback();
  return;
}

استفاده از catch با «وعده‌ها»

اگر تابع شما دارای تلاش مجدد فعال باشد، هر خطای مدیریت‌نشده‌ای باعث راه‌اندازی تلاش مجدد می‌شود. مطمئن شوید که کد شما هرگونه خطایی را که نباید منجر به تلاش مجدد شود، ثبت می‌کند.

در اینجا نمونه‌ای از کاری که باید انجام دهید آورده شده است:

return doFooAsync().catch((err) => {
    if (isFatal(err)) {
        console.error(`Fatal error ${err}`);
    }
    return Promise.reject(err);
});

توابع رویدادمحور قابل‌امتحان مجدد را خودتوان کنید

توابع رویدادمحور که می‌توانند دوباره امتحان شوند باید خودتوان باشند. در اینجا چند دستورالعمل کلی برای ساختن چنین تابعی به‌صورت خودتوان آورده شده است:

  • بسیاری از میاناهای برنامه‌سازی کاربردی خارجی (مثل Stripe) به شما اجازه می‌دهند کلید یک‌سان‌سازی را به‌عنوان پارامتر ارائه دهید. اگر از چنین میانای برنامه کاربردی استفاده می‌کنید، باید از شناسه رویداد به‌عنوان کلید «خودتوان‌سازی» استفاده کنید.
  • خاصیت خودتوان‌نمایی با تحویل حداقل یک‌بار به‌خوبی کار می‌کند، زیرا باعث می‌شود تلاش مجدد ایمن باشد. بنابراین، یک روال مطلوب کلی برای نوشتن کد قابل‌اعتماد این است که هم‌نهادی را با تلاش مجدد ترکیب کنید.
  • مطمئن شوید که کد شما به‌صورت داخلی خودتوان است. برای مثال:
    • مطمئن شوید که جهش‌ها می‌توانند بیش‌از یک‌بار بدون تغییر نتیجه رخ دهند.
    • وضعیت پایگاه داده را در تراکنش قبل‌از تغییر دادن وضعیت پُرسمان کنید.
    • مطمئن شوید که همه عوارض جانبی خودشان پایا باشند.
  • بررسی تراکنش را خارج از تابع و مستقل از کد اعمال کنید. برای مثال، وضعیت را در جایی که ثبت می‌کند شناسه رویداد معینی قبلاً پردازش شده است حفظ کنید.
  • با فراخوانی‌های تابع تکراری خارج از باند برخورد کنید. برای مثال، فرایند پاک‌سازی جداگانه‌ای داشته باشید که پس‌از فراخوانی‌های تابع تکراری پاک‌سازی می‌کند.

پیکربندی خط‌مشی تلاش مجدد

بسته به نیازهای تابع خود، ممکن است بخواهید خط‌مشی تلاش مجدد را مستقیماً پیکربندی کنید. این کار به شما امکان می‌دهد هر ترکیبی از موارد زیر را تنظیم کنید:

  • بازه زمانی تلاش مجدد را از ۷ روز به حداقل ۱۰ دقیقه کاهش دهید.
  • حداقل و حداکثر زمان بازگشت برای استراتژی تلاش مجدد با بازگشت نمایی را تغییر دهید.
  • استراتژی تلاش مجدد را به تلاش مجدد فوری تغییر دهید.
  • موضوع پیام‌های ناموفق را پیکربندی کنید.
  • حداکثر و حداقل تعداد تلاش برای ارسال را تنظیم کنید.

برای پیکربندی خط‌مشی تلاش مجدد:

  1. یک تابع HTTP بنویسید.
  2. از Pub/Sub API برای ایجاد اشتراک Pub/Sub استفاده کنید و نشانی وب تابع را به‌عنوان هدف مشخص کنید.

برای کسب اطلاعات بیشتر درباره پیکربندی مستقیم Pub/Sub، به مستندسازی Pub/Sub درباره مدیریت خطاها مراجعه کنید.