ניסיון חוזר של פונקציות אסינכרוניות

במסמך הזה מוסבר איך ניתן לשלוח בקשה אסינכרונית (לא HTTPS) פונקציות ברקע לבצע ניסיון חוזר במקרה של כשל.

הסמנטיקה של הניסיונות החוזרים

Cloud Functions מספק לפחות הפעלה אחת של פונקציה מבוססת-אירוע לכל אירוע שנשלח על ידי מקור האירוע. כברירת מחדל, אם פונקציה ההפעלה מסתיימת בשגיאה, הפונקציה לא מופעלת שוב. והאירוע מושמט. כשמפעילים ניסיונות חוזרים באירוע מבוסס-אירוע הפונקציה, Cloud Functions ינסה להפעיל שוב פונקציה שנכשלה עד הפעולה תסתיים בהצלחה או שחלון הזמן של הניסיונות החוזרים יפוג.

בפונקציות של דור שני, התוקף של חלון הניסיונות החוזרים יפוג אחרי 24 שעות. לפונקציות מדור ראשון, התוקף פג אחרי 7 ימים. Cloud Functions מבצע ניסיונות חוזרים לפונקציות מבוססות-אירועים שנוצרו לאחרונה באמצעות אסטרטגיה של השהיה מעריכית לפני ניסיון חוזר (exponential backoff), עם השהיה הולכת וגדלה של בין 10 ל-600 שניות. המדיניות הזו חלה על פונקציות חדשות בפעם הראשונה לפרוס אותם. הוא לא חל באופן רטרואקטיבי על נכסים קיימים והפונקציות שנפרסו לראשונה לפני השינויים שתוארו נתוני הגרסה האלה נכנסו לתוקף, גם אם תפרסו מחדש את הפונקציות.

כשלא מפעילים ניסיונות חוזרים לפונקציה שהיא ברירת המחדל, הפונקציה מדווח תמיד שההפעלה בוצעה בהצלחה, וקודי תגובה של 200 OK עשויים יופיעו ביומנים שלו. זה קורה גם אם הפונקציה נתקלה בשגיאה. שפת תרגום תבהירו כשהפונקציה נתקלת בשגיאה, הקפידו דיווח על שגיאות המתאים.

למה פונקציות מבוססות-אירועים לא הושלמו

במקרים נדירים, פונקציה עשויה לצאת מוקדם מדי עקב שגיאה פנימית, וכברירת מחדל, יכול להיות שלא יתבצע ניסיון חוזר אוטומטי של הפונקציה.

בדרך כלל, פונקציה מבוססת-אירוע עשויה להיכשל בשל כך לשגיאות שמוזנות בקוד הפונקציה עצמו. סיבות אפשריות לכך יכולים לכלול:

  • הפונקציה מכילה באג וסביבת זמן הריצה גורמת לחריגה.
  • הפונקציה לא יכולה להגיע לנקודת קצה (endpoint) של שירות, או שתם הזמן הקצוב לתפוגה במהלך הניסיון לעשות זאת.
  • הפונקציה גורמת לחריגה באופן מכוון (לדוגמה, כשפרמטר האימות נכשל).
  • פונקציית Node.js מחזירה הבטחה שנדחתה, או מעבירה ערך שאינו null אל קריאה חוזרת (callback).

בכל אחד מהמקרים האלה, הפונקציה מפסיקה לפעול כברירת מחדל והאירוע נמחק. כדי לנסות שוב את הפונקציה כשמתרחשת שגיאה: שנה את מדיניות ברירת המחדל לניסיונות חוזרים על ידי הגדרת 'ניסיון חוזר במקרה של כשל' לנכס. כתוצאה מכך, המערכת תנסה שוב ושוב לבצע את האירוע עד שהפונקציה תושלם בהצלחה או שתוקף הזמן הקצוב לניסיון חוזר יפוג.

הפעלה או השבתה של ניסיונות חוזרים

הגדרת ניסיונות חוזרים מהמסוף

אם יוצרים פונקציה חדשה:

  1. מתוך במסך Create Function (יצירת פונקציה), בקטע טריגר ובוחרים את סוג האירוע שישמש כטריגר מותאמת אישית.
  2. מסמנים את התיבה Retry on failure כדי להפעיל ניסיונות חוזרים.

אם אתם מעדכנים פונקציה קיימת:

  1. בדף Cloud Functions סקירה כללית, לוחצים על השם של שמעדכנים כדי לפתוח את המסך פרטי הפונקציה שלה, ואז בסרגל התפריטים, בוחרים באפשרות עריכה כדי להציג את החלונית טריגר.
  2. מסמנים או מבטלים את הסימון של התיבה Retry on failure כדי להפעיל או להשבית ניסיונות חוזרים.

הגדרת ניסיונות חוזרים מקוד הפונקציה

בעזרת Cloud Functions for Firebase אפשר להפעיל ניסיונות חוזרים בקוד של פונקציה. לעשות זאת בשביל פונקציה ברקע כמו functions.foo.onBar(myHandler);, שימוש runWith ומגדירים מדיניות כשל:

functions.runWith({failurePolicy: true}).foo.onBar(myHandler);

אם מגדירים את true כפי שמוצג, הפונקציה קובעת ניסיון חוזר במקרה של כשל.

שיטות מומלצות

בקטע הזה מתוארות שיטות מומלצות לשימוש בניסיונות חוזרים.

שימוש חוזר בשגיאות זמניות

מכיוון שניסיונות חוזרים של הפונקציה מתבצע באופן רציף עד שהפעולה תתבצע בהצלחה, למחוק שגיאות קבועות כמו באגים מהקוד באמצעות בדיקה לפני שמפעילים ניסיונות חוזרים. מומלץ לבצע ניסיונות חוזרים לטיפול לסירוגין או זמניים כשלים שיש להם סבירות גבוהה לפתרון במהלך ניסיון חוזר, כמו נקודת קצה רעועה של שירות או זמן קצוב לתפוגה.

צריך להגדיר תנאי סיום כדי להימנע מלולאות אינסופיות של ניסיונות חוזרים

מומלץ להגן על הפונקציה מפני לולאה רציפה כאשר באמצעות ניסיונות חוזרים. כדי לעשות זאת, אתם יכולים לכלול תנאי סיום מוגדר היטב, לפני שהעיבוד של הפונקציה מתחיל. שימו לב שהשיטה הזו פועלת רק אם הפונקציה מתחילה בהצלחה ויכולה להעריך את תנאי הסיום.

גישה פשוטה אבל יעילה היא למחוק אירועים עם חותמות זמן מלפני יותר מ- פרק זמן מסוים. כך ניתן למנוע הפעלות מוגזמות במקרים של כשלים מתמידים או ארוכים יותר מהצפוי.

לדוגמה, קטע הקוד הבא מוחק את כל האירועים שהתרחשו לפני יותר מ-10 שניות:

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

הגדרה של פונקציות מבוססות-אירועים שניתנות לניסיון חוזר

פונקציות מבוססות-אירועים שאפשר לבצע להן ניסיון חוזר חייבות להיות אידמפוטנטיות. הנה כמה דוגמאות הנחיות כלליות ליצירת פונקציה אידמפוטנטית כזו:

  • הרבה ממשקי API חיצוניים (כמו Stripe) מאפשרים לכם לספק מפתח אידמפוטנטיות. בתור פרמטר. אם אתם משתמשים בממשק API כזה, עליכם להשתמש במזהה האירוע באופן הבא: מפתח האידמפוטנטיות.
  • האידמפוטנטיות פועלת היטב במסירה פעם אחת לפחות, כי היא בטוחה לנסות שוב. לכן, שיטה מומלצת לכתיבה של קוד מהימן היא לשלב בין אי-תלותיות ברצף לבין ניסיונות חוזרים.
  • מוודאים שהקוד אידמפוטנטי באופן פנימי. לדוגמה:
    • מוודאים שמוטציות יכולות להתרחש יותר מפעם אחת, בלי לשנות את את התוצאה הרצויה.
    • מצב מסד הנתונים של השאילתות בטרנזקציה לפני שינוי המדינה.
    • חשוב לוודא שגם כל תופעות הלוואי הן אידמפוטנטיות.
  • לבצע בדיקת עסקה מחוץ לפונקציה, ללא קשר לקוד. לדוגמה, תוכלו לשמור את המצב במקום מסוים שבו נשמר מזהה אירוע מסוים כבר עובד.
  • טיפול בקריאות פונקציה כפולות מחוץ למסגרת. לדוגמה, לביצוע פינוי מקום בנפרד מתנקה אחרי הפעלות כפולות של פונקציות.

הגדרת מדיניות הניסיונות החוזרים

בהתאם לצורכי הפונקציה שלכם, יכול להיות שתרצו להגדיר ביצוע ניסיון חוזר של המדיניות ישירות. כך אפשר להגדיר כל שילוב של הבאים:

  • צריך לקצר את חלון הניסיון החוזר מ-7 ימים ל-10 דקות לכל היותר.
  • שינוי הזמן המינימלי והמקסימלי לפני ניסיון חוזר של השהיה מעריכית לפני ניסיון חוזר (exponential backoff) אסטרטגיה של ניסיונות חוזרים.
  • כדי לבצע ניסיון חוזר באופן מיידי, צריך לשנות את האסטרטגיה של הניסיונות החוזרים.
  • הגדרה של נושא של אותיות מתות.
  • מגדירים מספר מקסימלי ומינימלי של ניסיונות מסירה.

כדי להגדיר את מדיניות הניסיונות החוזרים:

  1. כותבים פונקציית HTTP.
  2. צריך להשתמש ב-API של Pub/Sub כדי ליצור מינוי ל-Pub/Sub, ולציין את כתובת ה-URL של את הפונקציה בתור היעד.

אפשר לעיין במסמכי העזרה בנושא Pub/Sub בנושא טיפול בכשלים לקבלת מידע נוסף על הגדרה ישירה של Pub/Sub.