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

این سند توضیح می‌دهد که چگونه می‌توانید درخواست کنید که توابع پس‌زمینه ناهمگام (غیر 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 با Promises

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

در اینجا مثالی از آنچه باید انجام دهید آورده شده است:

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

تکرارپذیر کردن توابع رویدادمحور قابل‌تکرار

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

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

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

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

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

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

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

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