הסבר על שגיאות API

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

‫Data Manager API פועל לפי מודל השגיאות הרגיל של Google API, שמבוסס על קודי הסטטוס של gRPC. כל תגובה מה-API שגורמת לשגיאה כוללת אובייקט Status עם:

  • קוד שגיאה מספרי.
  • הודעת שגיאה.
  • אופציונלי, פרטים נוספים על השגיאה.

קודי שגיאה קנוניים

‫Data Manager API משתמש בקבוצה של קודי שגיאה קנוניים שמוגדרים על ידי gRPC ו-HTTP. הקודים האלה מספקים אינדיקציה כללית לגבי סוג השגיאה. תמיד כדאי לבדוק קודם את הקוד הזה כדי להבין את מהות הבעיה.

לפרטים נוספים על הקודים האלה, ראו מדריך לעיצוב API – קודי שגיאה.

מודל של כישלון מהיר

‫Data Manager API משתמש במודל של כשל מהיר. אם בקשה מכילה שגיאות מבניות או אם רשומה כלשהי נכשלת באימות של שדה חובה, הבקשה כולה נכשלת וה-API לא מעבד את הנתונים בבקשה הזו.

השוואה למודל הכישלון החלקי

מודל הכישלון המהיר שונה ממודל הכישלון החלקי בממשקי API אחרים של Google, כמו Google Ads API ו-Campaign Manager 360 API. במודל של כישלון חלקי, הבקשה מצליחה גם אם בחלק מהרשומות יש שגיאות, והתשובה מכילה פרטי שגיאה לגבי הרשומות שנכשלו.

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

מודל הכשל המהיר מונע את הבעיות האלה על ידי התראה מיידית על בעיות בנתונים או בשילוב, כדי שתוכלו לנקוט את הפעולה המתאימה.

בדיקה אם יש שגיאות מסוג fast-fail באמצעות validateOnly

רוב הבקשות להטמעת נתונים ובקשות להסרת תוכן תומכות בשדה validateOnly. כשמגדירים את validateOnly לערך true, ה-Data Manager API מריץ את אותן בדיקות אימות בסיסיות כמו בבקשה רגילה, אבל לא מטמיע או מסיר נתונים.

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

אפשר להשתמש בvalidateOnly כדי:

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

טיפול בשגיאות

אם הבקשה נכשלת, פועלים לפי השלבים הבאים:

  1. בודקים את קוד השגיאה כדי לזהות את סוג השגיאה.

    • אם אתם משתמשים ב-gRPC, קוד השגיאה מופיע בשדה code של Status. אם אתם משתמשים בספריית לקוח, יכול להיות שהיא תציג סוג ספציפי של חריגה שתואם לקוד השגיאה. לדוגמה, ספריית הלקוח של Java מחזירה com.google.api.gax.rpc.InvalidArgumentException אם קוד השגיאה הוא INVALID_ARGUMENT.
    • אם אתם משתמשים ב-REST, קוד השגיאה נמצא בתגובת השגיאה ב-error.status, וסטטוס ה-HTTP התואם נמצא ב-error.code.
  2. בודקים את מטען הייעודי (payload) של הפרטים הסטנדרטיים של קוד השגיאה. מטעני הייעודיים הסטנדרטיים של הפרטים הם קבוצת הודעות לשגיאות מ-Google APIs. הם מספקים פרטים על השגיאה בצורה מובנית ועקבית. כל שגיאה מ-Data Manager API יכולה לכלול כמה הודעות מטען ייעודי (payload) עם פרטים סטנדרטיים. בספריות הלקוח של Data Manager API יש שיטות עזר לקבלת המטענים הייעודיים (payloads) הסטנדרטיים של פרטי השגיאה.

    לא משנה מה קוד השגיאה, מומלץ לבדוק את המטענים הייעודיים (payloads) של ErrorInfo,‏ RequestInfo,‏ Help ו-LocalizedMessage ולתעד אותם ביומן.

    • השדה ErrorInfo מכיל מידע שאולי לא מופיע במטענים ייעודיים אחרים.
    • ‫RequestInfo מכיל את מזהה הבקשה, שיכול לעזור אם צריך לפנות לתמיכה.
    • השגיאות Help ו-LocalizedMessage מכילות קישורים ופרטים נוספים שיעזרו לכם לטפל בשגיאה.

    בנוסף, המטען הייעודי (payload) של BadRequest שימושי לשגיאות INVALID_ARGUMENT כי הוא מספק מידע על השדות שגרמו לשגיאה.

אזהרות לגבי הטמעה

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

תגובת הטמעה מוצלחת (קוד סטטוס של HTTP‏ 200) כוללת את האזהרות האלה ברשימת fieldWarnings. כל רשומה היא אובייקט FieldWarning עם השדות הבאים:

field

המיקום של השדה בבקשה, בתחביר נתיב של קו תחתון בין המילים.

אם נתיב מצביע לפריט ברשימה (שדה repeated), האינדקס שלו מוצג בסוגריים מרובעים ([...]) אחרי שם הרשימה.

לדוגמה, events.events[0].cart_data.items[0].merchant_product_id מזהה אזהרה שקשורה לפריט הראשון בנתוני עגלת הקניות של האירוע הראשון בבקשה.

description

הסבר למה הערך שצוין גרם לאזהרה.

reason

ערך ה-enum של WarningReason שמזהה את סוג האזהרה.

דוגמה עם FieldWarning

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

{
  "requestId": "126365e1-16d0-4c81-9de9-f362711e250a",
  "fieldWarnings": [
    {
      "field": "events.events[0].cart_data.items[0].merchant_product_id",
      "description": "The merchant product ID is missing in the cart item.",
      "reason": "WARNING_REASON_CART_DATA_ITEM_MERCHANT_PRODUCT_ID_MISSING"
    }
  ]
}

מטענים ייעודיים (payloads) סטנדרטיים של פרטים

אלה המטענים הייעודיים (payloads) הנפוצים ביותר של פרטים סטנדרטיים ב-Data Manager API:

BadRequest

בודקים את המטען הייעודי (payload) של BadRequest כשבקשה נכשלת עם השגיאה INVALID_ARGUMENT (קוד סטטוס של HTTP‏ 400).

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

field

המיקום של השדה בבקשה, בתחביר של נתיב עם קו תחתון בין המילים.

אם נתיב מצביע לפריט ברשימה (שדה repeated), האינדקס שלו מוצג בסוגריים מרובעים ([...]) אחרי שם הרשימה.

לדוגמה, destinations[0].operating_account.account_id הוא account_id ב-operating_account של הפריט הראשון ברשימה destinations.

description

הסבר למה הערך גרם לשגיאה.

reason

הערך של ErrorReason, למשל INVALID_HEX_ENCODING או INVALID_CURRENCY_CODE.

דוגמאות של BadRequest

הנה דוגמה לתגובה לשגיאה מסוג INVALID_ARGUMENT עם הודעה מסוג BadRequest. השגיאה field_violations מציינת שהערך accountId הוא לא מספר. הערך field destinations[0].login_account.account_id מראה שה-accountId עם הפרת השדה נמצא ב-login_account של הפריט הראשון ברשימה destinations.

{
  "error": {
    "code": 400,
    "message": "There was a problem with the request.",
    "status": "INVALID_ARGUMENT",
    "details": [
      {
        "@type": "type.googleapis.com/google.rpc.ErrorInfo",
        "reason": "INVALID_ARGUMENT",
        "domain": "datamanager.googleapis.com",
        "metadata": {
          "requestId": "t-a8896317-069f-4198-afed-182a3872a660"
        }
      },
      {
        "@type": "type.googleapis.com/google.rpc.RequestInfo",
        "requestId": "t-a8896317-069f-4198-afed-182a3872a660"
      },
      {
        "@type": "type.googleapis.com/google.rpc.BadRequest",
        "fieldViolations": [
          {
            "field": "destinations[0].login_account.account_id",
            "description": "String is not a valid number.",
            "reason": "INVALID_NUMBER_FORMAT"
          }
        ]
      }
    ]
  }
}

הנה עוד דוגמה לתגובה לשגיאה INVALID_ARGUMENT עם הודעת BadRequest. בדוגמה הזו, ברשימה field_violations מוצגות שתי שגיאות:

  1. הערך של event הראשון לא מקודד בפורמט הקסדצימלי במזהה המשתמש השני של האירוע.

  2. השדה השני event מכיל ערך שלא מקודד בפורמט הקסדצימלי במזהה המשתמש השלישי של האירוע.

{
  "error": {
    "code": 400,
    "message": "There was a problem with the request.",
    "status": "INVALID_ARGUMENT",
    "details": [
      {
        "@type": "type.googleapis.com/google.rpc.ErrorInfo",
        "reason": "INVALID_ARGUMENT",
        "domain": "datamanager.googleapis.com",
        "metadata": {
          "requestId": "t-6bc8fb83-d648-4942-9c49-2604276638d8"
        }
      },
      {
        "@type": "type.googleapis.com/google.rpc.RequestInfo",
        "requestId": "t-6bc8fb83-d648-4942-9c49-2604276638d8"
      },
      {
        "@type": "type.googleapis.com/google.rpc.BadRequest",
        "fieldViolations": [
          {
            "field": "events.events[0].user_data.user_identifiers[1]",
            "description": "The HEX encoded value is malformed.",
            "reason": "INVALID_HEX_ENCODING"
          },
          {
            "field": "events.events[1].user_data.user_identifiers[2]",
            "description": "The HEX encoded value is malformed.",
            "reason": "INVALID_HEX_ENCODING"
          }
        ]
      }
    ]
  }
}

RequestInfo

בכל פעם שבקשה נכשלת, בודקים את המטען הייעודי (payload) של RequestInfo. RequestInfo מכיל את request_id שמזהה באופן ייחודי את בקשת ה-API שלכם.

{
  "@type": "type.googleapis.com/google.rpc.RequestInfo",
  "requestId": "t-4490c640-dc5d-4c28-91c1-04a1cae0f49f"
}

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

ErrorInfo

חפשו את ההודעה ErrorInfo כדי לאחזר מידע נוסף שאולי לא נלכד במטענים הייעודיים (payloads) האחרים של הפרטים הרגילים. המטען הייעודי (payload) של ErrorInfo מכיל מפה של metadata עם מידע על השגיאה.

לדוגמה, הנה ErrorInfo של כשל ב-PERMISSION_DENIED שנגרם כתוצאה משימוש בפרטי כניסה לפרויקט בענן של Google Cloud שבו Data Manager API לא מופעל. השדה ErrorInfo מספק מידע נוסף על השגיאה, כמו:

  • הפרויקט שמשויך לבקשה, בקטע metadata.consumer.
  • שם השירות, בקטע metadata.serviceTitle.
  • כתובת ה-URL שבה אפשר להפעיל את השירות, בקטע metadata.activationUrl.
{
  "error": {
    "code": 403,
    "message": "Data Manager API has not been used in project PROJECT_NUMBER before or it is disabled. Enable it by visiting https://console.cloud.google.com/apis/api/datamanager.googleapis.com/overview?project=PROJECT_NUMBER then retry. If you enabled this API recently, wait a few minutes for the action to propagate to our systems and retry.",
    "status": "PERMISSION_DENIED",
    "details": [
      {
        "@type": "type.googleapis.com/google.rpc.ErrorInfo",
        "reason": "SERVICE_DISABLED",
        "domain": "googleapis.com",
        "metadata": {
          "consumer": "projects/PROJECT_NUMBER",
          "service": "datamanager.googleapis.com",
          "containerInfo": "PROJECT_NUMBER",
          "serviceTitle": "Data Manager API",
          "activationUrl": "https://console.cloud.google.com/apis/api/datamanager.googleapis.com/overview?project=PROJECT_NUMBER"
        }
      },
      ...
    ]
  }
}

שגיאות שקשורות למכסות ולהגבלת קצב של יצירת בקשות

אם בקשה חורגת ממגבלת הפרויקט, ה-API מחזיר שגיאת RESOURCE_EXHAUSTED (קוד סטטוס של HTTP‏ 429). המטען הייעודי (payload) של ErrorInfo מספק פרטים על המגבלה שנחרגה במפה metadata:

consumer
‫
הפרויקט בענן של Google שמשויך לבקשה, בפורמט projects/PROJECT_NUMBER.
quota_limit
‫
: השם של מגבלת המכסה שנחרגה, למשל IngestionMutateRequestsPerMinutePerProject או IngestionMutateRequestsPerDayPerProject. אתם יכולים להשתמש בערך הזה כדי לקבוע אם האפליקציה חרגה מהמגבלה לדקה או מהמגבלה היומית. לרשימה המלאה של שמות המגבלות, ראו מגבלות לפרויקטים.
quota_location
המיקום שבו המכסה נאכפת. ב-Data Manager API, הערך הזה הוא תמיד global.
quota_metric
המדד שמשויך למגבלה, כמו datamanager.googleapis.com/ingestion_mutate_requests.
service
‫
שם השירות, datamanager.googleapis.com.

דוגמה לתגובת שגיאה מסוג RESOURCE_EXHAUSTED כשבקשה חורגת מהמגבלה לדקה של בקשות לשינוי נתונים בהטמעה:

{
  "error": {
    "code": 429,
    "message": "Quota exceeded for quota metric 'Ingestion mutate requests' and limit 'Ingestion mutate requests per minute' of service 'datamanager.googleapis.com' for consumer 'project_number:PROJECT_NUMBER'.",
    "status": "RESOURCE_EXHAUSTED",
    "details": [
      {
        "@type": "type.googleapis.com/google.rpc.ErrorInfo",
        "reason": "RATE_LIMIT_EXCEEDED",
        "domain": "googleapis.com",
        "metadata": {
          "consumer": "projects/PROJECT_NUMBER",
          "quota_limit": "IngestionMutateRequestsPerMinutePerProject",
          "quota_location": "global",
          "quota_metric": "datamanager.googleapis.com/ingestion_mutate_requests",
          "service": "datamanager.googleapis.com"
        }
      }
    ]
  }
}

Help וגם LocalizedMessage

כדי לקבל קישורים למסמכי תיעוד ולהודעות שגיאה מקומיות שיעזרו לכם להבין את השגיאה ולתקן אותה, חפשו את המטענים הייעודיים (payloads) Help ו-LocalizedMessage.

לדוגמה, הנה Help ו-LocalizedMessage של כשל ב-PERMISSION_DENIED שנגרם כתוצאה משימוש בפרטי כניסה לפרויקט בענן ב-Google Cloud שבו Data Manager API לא מופעל. המטען הייעודי (payload) של Help מציג את כתובת ה-URL שבה אפשר להפעיל את השירות, וב-LocalizedMessage יש תיאור של השגיאה.

{
  "error": {
    "code": 403,
    "message": "Data Manager API has not been used in project PROJECT_NUMBER before or it is disabled. Enable it by visiting https://console.cloud.google.com/apis/api/datamanager.googleapis.com/overview?project=PROJECT_NUMBER then retry. If you enabled this API recently, wait a few minutes for the action to propagate to our systems and retry.",
    "status": "PERMISSION_DENIED",
    "details": [
      {
        "@type": "type.googleapis.com/google.rpc.LocalizedMessage",
        "locale": "en-US",
        "message": "Data Manager API has not been used in project PROJECT_NUMBER before or it is disabled. Enable it by visiting https://console.cloud.google.com/apis/api/datamanager.googleapis.com/overview?project=PROJECT_NUMBER then retry. If you enabled this API recently, wait a few minutes for the action to propagate to our systems and retry."
      },
      {
        "@type": "type.googleapis.com/google.rpc.Help",
        "links": [
          {
            "description": "Google API Console API activation",
            "url": "https://console.cloud.google.com/apis/api/datamanager.googleapis.com/overview?project=PROJECT_NUMBER"
          }
        ]
      },
      ...
    ]
  }
}

פרטי שגיאת הגישה

אם אתם משתמשים באחת מספריות הלקוח, השתמשו בשיטות העזר כדי לקבל את המטענים הייעודיים (payloads) הסטנדרטיים של הפרטים.

‎.NET

try {
    // Send API request
}
catch (Grpc.Core.RpcException rpcException)
{
    Console.WriteLine($"Exception encountered: {rpcException.Message}");
    var statusDetails =
        Google.Api.Gax.Grpc.RpcExceptionExtensions.GetAllStatusDetails(
            rpcException
        );
    foreach (var detail in statusDetails)
    {
        if (detail is Google.Rpc.BadRequest)
        {
            Google.Rpc.BadRequest badRequest = (Google.Rpc.BadRequest)detail;
            foreach (
                BadRequest.Types.FieldViolation? fieldViolation in badRequest.FieldViolations
            )
            {
                // Access attributes such as fieldViolation!.Reason and fieldViolation!.Field
            }
        }
        else if (detail is Google.Rpc.RequestInfo)
        {
            Google.Rpc.RequestInfo requestInfo = (Google.Rpc.RequestInfo)detail;
            string requestId = requestInfo.RequestId;
            // Log the requestId...
        }
        else if (detail is Google.Rpc.ErrorInfo)
        {
            Google.Rpc.ErrorInfo errorInfo = (Google.Rpc.ErrorInfo)detail;
            // Log the errorInfo.Reason and errorInfo.Metadata...

            // If handling a rate limit error, check the exceeded quota limit:
            if (errorInfo.Reason == "RATE_LIMIT_EXCEEDED" &&
                errorInfo.Metadata.TryGetValue("quota_limit", out string quotaLimit))
            {
                // Inspect quotaLimit to determine whether it is a per-minute
                // or daily limit (for example,
                // IngestionMutateRequestsPerMinutePerProject).
            }

            // Log the details in the 'Metadata' map...
            foreach (
                KeyValuePair<String, String> metadataEntry in errorInfo.Metadata
            )
            {
                // Log the metadataEntry.Key and metadataEntry.Value...
            }
        }
        else
        {
            // ...
        }
    }
}

Java

try {
  // Send API request
} catch (com.google.api.gax.rpc.InvalidArgumentException invalidArgumentException) {
  // Gets the standard BadRequest payload from the exception.
  BadRequest badRequest = invalidArgumentException.getErrorDetails().getBadRequest();
  for (int i = 0; i < badRequest.getFieldViolationsCount(); i++) {
    FieldViolation fieldViolation = badRequest.getFieldViolations(i);
    // Access attributes such as fieldViolation.getField() and fieldViolation.getReason()
  }

  // Gets the standard RequestInfo payload from the exception.
  RequestInfo requestInfo = invalidArgumentException.getErrorDetails().getRequestInfo();
  if (requestInfo != null) {
    String requestId = requestInfo.getRequestId();
    // Log the requestId...
  }
} catch (com.google.api.gax.rpc.ApiException apiException) {
  // Fallback exception handler for other types of ApiException.

  // Gets the standard ErrorInfo payload from the exception.
  ErrorInfo errorInfo = apiException.getErrorDetails().getErrorInfo();
  // Log the 'reason' and 'domain'...

  // If handling a rate limit error, check the exceeded quota limit:
  if (errorInfo != null && "RATE_LIMIT_EXCEEDED".equals(errorInfo.getReason())) {
    String quotaLimit = errorInfo.getMetadataMap().get("quota_limit");
    // Inspect quotaLimit to determine whether it is a per-minute
    // or daily limit (for example,
    // IngestionMutateRequestsPerMinutePerProject).
  }

  // Log the details in the 'metadata' map...
  for (Entry<String, String> metadataEntry : errorInfo.getMetadataMap().entrySet()) {
    // Log the metadataEntry key and value...
  }

  // Gets the standard RequestInfo payload from the exception.
  RequestInfo requestInfo = apiException.getErrorDetails().getRequestInfo();
  if (requestInfo != null) {
    String requestId = requestInfo.getRequestId();
    // Log the requestId...
  }
  ...
}

טיפול בשגיאות שקשורות לגודל הכותרת ב-gRPC

אם מספר גדול של רשומות בבקשה להטמעת נתונים או בבקשה להסרת תוכן נכשל באימות, ה-Data Manager API מחזיר את כל השגיאות במטען הייעודי (payload) של BadRequest בתגובה.

ב-gRPC, השירות מחזיר את פרטי השגיאה האלה בכותרות התגובה של HTTP/2 (מטא-נתונים). כברירת מחדל, ספריות הלקוח של gRPC מגבילות את הכותרות הנכנסות לגודל מקסימלי (בדרך כלל 8-10KB). אם פרטי השגיאה חורגים מהמגבלה הזו, ההעברה של HTTP/2 בצד הלקוח נכשלת לפני ניתוח התגובה לשגיאה, ומופיעה חריגה כמו:

Http2Exception: Header size exceeded max allowed size (10240)

הלקוח לא יכול לעבד את כותרות התגובה, ולכן הוא מבטל את הסטרימינג (שמופיע כסטטוס HTTP‏ 499 Client Closed Request ביומנים בצד השרת), והאפליקציה לא יכולה לגשת לפרטי השגיאה BadRequest.

כדי לפתור את הבעיה ולבדוק את רשימת השגיאות המלאה, צריך להגדיר את לקוח ה-gRPC עם גודל מטא-נתונים מקסימלי גדול יותר (למשל 16MB):

‎.NET

// Creates a client for the ingestion service. Increases the maximum metadata size to
// 16MB to prevent RESOURCE_EXHAUSTED errors when responses contain large error
// details.
IngestionServiceClient ingestionServiceClient = new IngestionServiceClientBuilder
{
    GrpcChannelOptions = GrpcChannelOptions.Empty.WithCustomOption(
        "grpc.max_metadata_size",
        16 * 1024 * 1024
    ),
}.Build();

Java

// Creates a client for the ingestion service. Increases the maximum metadata size to 16MB to
// prevent RESOURCE_EXHAUSTED errors when responses contain large error details.
InstantiatingGrpcChannelProvider provider =
    IngestionServiceSettings.defaultGrpcTransportProviderBuilder()
        .setMaxInboundMetadataSize(16 * 1024 * 1024)
        .build();
IngestionServiceSettings settings =
    IngestionServiceSettings.newBuilder().setTransportChannelProvider(provider).build();
try (IngestionServiceClient ingestionServiceClient = IngestionServiceClient.create(settings)) {
  // ...
}

צומת

// Creates a client for the ingestion service. Increases the maximum metadata
// size to 16MB to prevent RESOURCE_EXHAUSTED errors when responses contain
// large error details.
const client = new IngestionServiceClient({
  'grpc.max_metadata_size': 16 * 1024 * 1024,
});

PHP

// Creates a client for the ingestion service. Increases the maximum metadata size to 16MB to
// prevent RESOURCE_EXHAUSTED errors when responses contain large error details.
$client = new IngestionServiceClient([
    'transportConfig' => [
        'grpc' => [
            'stubOpts' => [
                'grpc.max_metadata_size' => 16 * 1024 * 1024,
            ],
        ],
    ],
]);

Python

# Creates a client for the ingestion service. Increases the maximum
# metadata size to 16MB to prevent RESOURCE_EXHAUSTED errors when responses
# contain large error details.
channel = datamanager_v1.services.ingestion_service.transports.IngestionServiceGrpcTransport.create_channel(
    options=[("grpc.max_metadata_size", 16 * 1024 * 1024)]
)
transport = datamanager_v1.services.ingestion_service.transports.IngestionServiceGrpcTransport(
    channel=channel
)
client: datamanager_v1.IngestionServiceClient = (
    datamanager_v1.IngestionServiceClient(transport=transport)
)

שיטות מומלצות לטיפול בשגיאות

כדי ליצור אפליקציות עמידות, כדאי ליישם את השיטות המומלצות הבאות.

אימות לפני השליחה
כשיוצרים או משנים שילוב, שולחים בקשות עם הערך true בשדה validateOnly כדי לזהות שגיאות שגורמות לכשל מהיר לפני הטמעת הנתונים.
בדיקת פרטי השגיאה
תמיד צריך לחפש את אחד ממטעני הייעודיים (payload) הסטנדרטיים של פרטים, כמו BadRequest. כל מטען ייעודי (payload) של פרטים סטנדרטיים מכיל מידע שיעזור לכם להבין את הסיבה לשגיאה.
הבחנה בין שגיאות בצד הלקוח לשגיאות בחיבור לשרת

בודקים אם השגיאה נגרמה בגלל בעיה בהטמעה (הלקוח) או בגלל בעיה ב-API (השרת).

  • שגיאות בצד הלקוח: קודים כמו INVALID_ARGUMENT, ‏ NOT_FOUND,‏ PERMISSION_DENIED, ‏ FAILED_PRECONDITION, ‏ UNAUTHENTICATED. כדי לפתור אותן, צריך לשנות את הבקשה או את המצב או פרטי הכניסה של האפליקציה. אל תנסו לשלוח שוב את הבקשה בלי לטפל בבעיה.
  • שגיאות בחיבור לשרת: קודים כמו UNAVAILABLE, ‏ INTERNAL,‏ DEADLINE_EXCEEDED, ‏ UNKNOWN. השגיאות האלה מצביעות על בעיה זמנית בשירות ה-API.
הטמעה של אסטרטגיית ניסיון חוזר

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

  • נסו שוב רק במקרה של שגיאות זמניות בחיבור לשרת (כמו UNAVAILABLE,‏ DEADLINE_EXCEEDED,‏ INTERNAL,‏ UNKNOWN ו-ABORTED) ובמקרה של הגבלות קצב לדקה (RESOURCE_EXHAUSTED עם RATE_LIMIT_EXCEEDED).

  • כדי לבדוק את מגבלות הקצב, בודקים את quota_limit ב-ErrorInfo:

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

    • אם המגבלה היא יומית (למשל IngestionMutateRequestsPerDayPerProject), אל תנסו שוב מיד. להשהות את העיבוד עד שהמכסה היומית תתאפס בחצות, לפי שעון החוף המערבי של ארה"ב.

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

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

תיעוד מפורט

מתעדים את תגובת השגיאה המלאה, כולל כל המטענים הייעודיים (payloads) של הפרטים הרגילים, במיוחד מזהה הבקשה. המידע הזה חיוני לניפוי באגים ולדיווח על בעיות לתמיכה של Google במקרה הצורך.

שליחת משוב ממשתמשים

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

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