برنامه نویسی

سفارشی کردن رسیدگی به خطا در توابع مرحله

ما می‌توانیم مدیریت خطا را در توابع مرحله با استفاده از فیلدهای Retry و Catch داخلی سفارشی کنیم. هنگام انتقال مسئولیت رسیدگی به خطا به توابع Step، می‌توانیم کدهای کوتاه‌تر و تمیزتر را در برنامه‌های خود بنویسیم.

1. رسیدگی به خطا بدون توابع مرحله

فرض کنید می‌خواهیم یک گردش کاری ایجاد کنیم که از چندین تابع Lambda و شاید برخی خدمات AWS دیگر تشکیل شده باشد.

ما می توانیم از چندین نوع مختلف روش های ارکستراسیون استفاده کنیم. برخی از آنها بهتر هستند و برخی از آنها کمتر مطلوب هستند.

در هر صورت، ما باید خطاها را مدیریت کنیم، و معمولاً این کار را در کد برنامه با نوشتن چیزی شبیه به این انجام می دهیم:

export async function handler(event) {
  const { taskId } = event;
  // get the task based on its ID from a 3rd party endpoint - pseudo code:
  let task;
  try {
    task = await getTaskById(taskId);
    return task;
  } catch (error) {
    logger.error('error while getting task', { taskId });
    throw error;
  }
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

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

اما اگر تکلیف باشد پیدا نشد و نقطه پایانی شخص 3 با a پاسخ می دهد 404 خطا؟ یا اعتبارسنجی برای پارامترهای رویداد با شکست مواجه می شود؟

این تابع می تواند هر چند بار که بخواهیم دوباره امتحان کند، اما نتیجه همیشه یکسان خواهد بود – یک خطا. آیا منطقی است که آن را دوباره با همان ورودی امتحان کنیم؟ احتمالا نه.

در این صورت می‌توانیم بررسی کنیم که آیا خطا دارای کد یا نام وضعیت خاصی است یا خیر. یک رویکرد ممکن می تواند به این صورت باشد:

class NotFoundError extends Error {
  constructor(message) {
    super(message);
    this.name = 'NotFoundError';
  }
}

async function getTaskById(taskId) {
  try {
    const task = await getTaskFromThirdParty(taskId);
    return task;
  } catch (error) {
    if (error.statusCode === 404) {
      throw new NotFoundError(`Task with ID ${taskId} is not found.`)
    }

    // otherwise rethrow the original error
    throw error
  }
}

export async function handler(event) {
  const { taskId } = event;

  let task;
  try {
    task = await getTaskById(taskId);
    return task;
  } catch (error) {
    if (error instanceof NotFoundError) {
      logger.error('task not found, no point trying again');
      return;
    }

    // We'll retry when getting other errors
    logger.error('error while getting task', { taskId });
    throw error;
  }
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

این کد زشت می شود و خواندن آن با آن سخت می شود if شرایط در catch مسدود کردن. تصور کنید که باید چندین نوع خطا را به طور متفاوت مدیریت کنیم. ممکن است منجر به کدهای پیچیده تر شود.

2. رسیدگی به خطا با توابع مرحله

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

2.1. مدیریت خطا را محول کنید

یکی از بسیاری از ویژگی های عالی Step Function این است که ما می توانیم بلند کردن مدیریت خطا از کد به ماشین حالت.

ما می توانیم یک وضعیت Task ایجاد کنیم که از آن توابع Step می توانند یک تابع Lambda را فراخوانی کنند. Workflow Studio ساخت یک ماشین حالت را با ابزار کشیدن و رها کردن عالی خود آسان می کند (خوب، آسان تر).

وقتی یک تابع لامبدا را به آن اضافه می کنیم Task ایالت، ما یک Retry فیلد در UI و تعریف ASL مربوطه (زبان ایالت آمازون، اساساً JSON با برخی ویژگی‌های خاص). به نظر می رسد این است:

"Retry": [
  {
    "ErrorEquals": [
      "States.TaskFailed"
    ],
    "BackoffRate": 2,
    "IntervalSeconds": 2,
    "MaxAttempts": 3,
    "Comment": "Some interesting comments about the field"
  }
]
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

2.2. فیلدها را دوباره امتحان کنید

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

را ErrorEquals آرایه حاوی انواع خطاهایی است که شی تکرار داده شده مربوط به آنهاست. States.TaskFailed شامل تقریباً تمام خطاهایی است که می تواند در حین اجرای یک کار رخ دهد، به عنوان مثال، استثناهایی که در برنامه، شبکه یا خطاهای زمان اجرا ایجاد می کنیم.

بنابراین هنگامی که هنگام اجرای تابع لامبدا خطایی رخ می دهد، سه بار دیگر امتحان می کنیم (MaxAttempts). IntervalSeconds و BackoffRate یک الگوی عقب نشینی نمایی ایجاد می کند. اولین تلاش مجدد در 2 ثانیه انجام می شود (IntervalSeconds، سپس توابع مرحله فاصله بین هر تلاش مجدد را دو برابر می کند ("BackoffRate": 2) تا زمانی که به حداکثر تعداد تلاش ها برسد.

2.3. رسیدگی به خطاهای سفارشی

همانطور که در بالا ذکر کردم، همه انواع خطاها نیازی به امتحان مجدد ندارند. می‌توانیم یک شی رسیدگی به خطای دیگر را به آن اضافه کنیم Retry آرایه به این صورت:

"Retry": [
  {
    "ErrorEquals": [
      "NotFoundError"
    ],
    "BackoffRate": 1,
    "IntervalSeconds": 0,
    "MaxAttempts": 0,
    "Comment": "No retries on NotFoundError"
  },
  {
    "ErrorEquals": [
      "States.TaskFailed"
    ],
    "BackoffRate": 2,
    "IntervalSeconds": 2,
    "MaxAttempts": 3,
    "Comment": "Some interesting comments about the field"
  }
]
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

تنظیم کردیم 0 به IntervalSeconds و MaxAttempts. این بدان معناست که ما نمی‌خواهیم توابع Step مجدداً تابع Lambda را فراخوانی کند. BackoffRate دارای حداقل مقدار اجباری است 1، بنابراین می توانیم آن را همانطور که هست رها کنیم.

را Retry عنصر یک آرایه است و توابع Step به ترتیب اشیاء آن را ارزیابی می کند. بنابراین ابتدا باید خطاهای سفارشی خود را بنویسیم و States.TaskFailed، که با هر خطای دیگری مطابقت دارد (برای موارد استثنا به ادامه مطلب مراجعه کنید)، در آخر خواهد آمد.

2.4. صید زمینه ها

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

به عنوان مثال، ما می خواهیم در صورت وجود a به تیم اطلاع دهیم NotFoundError. ما می خواهیم چیزی را که وجود ندارد پردازش کنیم و باید آن را درست کنیم!

یا، می‌خواهیم از مرحله شکست خورده بگذریم و خوشحالیم که بقیه جریان کار را ادامه دهیم.

در این موارد، ما مجبور خواهیم شد گرفتن خطاها

یکی از راه حل های ممکن این است که عوارض جانبی را در آن قرار دهید try/catch همانطور که در بالا دیدیم، در کد بلوک می شود. اما ما می‌توانیم این مسئولیت را به Step Functions که همراه با داخلی است، محول کنیم Catch رشته.

Catch در تعریف ماشین حالت در همان سطح است Retry. مشابه دوستش، آرایه ای نیز خواهد بود.

می تواند به این شکل باشد:

"Catch": [
  {
    "ErrorEquals": [
      "NotFoundError"
    ],
    "Comment": "Handling not found errors",
    "Next": "Send email notification",
    "ResultPath": "$.error"
  }
]
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

را ErrorEquals آرایه مانند بالا در است Retry، و خطاهایی را که می خواهیم با کنترل کننده سفارشی در اینجا پیدا کنیم را مشخص می کنیم.

را Next فیلد شامل حالت بعدی بعد از اینکه توابع مرحله ای هر کدام را گرفت می باشد NotFoundError. در این مورد، آن خواهد بود Send email notification حالت، که می تواند هر چیزی منطقی برای مورد استفاده باشد، به عنوان مثال، فراخوانی یک تابع Lambda دیگر یا انتشار یک پیام به یک موضوع SNS برای اعلان.

می توانیم شی خطا را به آن اضافه کنیم error دارایی در خروجی حالت (ResultPath). اگر ما این کار را انجام دهیم، دولتی که پرتاب می کند NotFoundError استثنا خروجی مشابه این خواهد داشت:

{
  "taskId": "TASK_ID",
  // ... other input properties here
  "error": {
    "Error": "NotFoundError",
    "Cause": "{\"errorType\":\"NotFoundError\",\"errorMessage\":\"Task \\
    with ID TASK_ID is not found\",\"trace\":[\"NotFoundError: Task with \\
    ID TASK_ID is not found\",\"    at Runtime.handler \\
    (file:///var/task/index.mjs:12:11)\",\" at Runtime.handleOnceNonStreaming \\
    (file:///var/runtime/index.mjs:1086:29)\"]}"
  }
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

البته این شی JSON وضعیت بعدی خواهد بود ورودی، در مورد ما، Send email notification. این ایالت قرار است یک ایمیل با پیام خطا برای اعضای تیم ارسال کند.

ما می توانیم اشیاء بیشتری را به آن اضافه کنیم Catch یا فقط یکی با States.TaskFailed یا States.ALL برای اجرای منطق سفارشی زمانی که (تقریبا) هر نوع خطایی رخ می دهد.

3. همه چیز را کنار هم قرار دهید

ماشین حالت فوق العاده ساده ما به این شکل است:

دستگاه حالت با مدیریت خطای سفارشی

وقتی اولین حالت (Get task from 3rd party) الف را پرتاب می کند NotFoundError، Step Functions قبل از اینکه اجرا ناموفق باشد، یک اعلان ایمیل با پیام خطا برای مشترکین ارسال می کند. فراموش نکنید که ALLOW را SNS:Publish اگر بخواهید اعلان ارسال کنید، در نقش IAM تابع Step عمل کنید.

اگر خطایی رخ ندهد، توابع مرحله ای رخ خواهد داد Do something with the task در حالت بعدی

اگر در هر یک از مراحل خطای دیگری رخ دهد، اجرا با شکست مواجه خواهد شد.

یک مزیت بزرگ استفاده از رویکرد مورد بحث در بالا این است که کنترل کننده تابع Lambda ما بسیار ساده می شود:

export async function handler(event) {
  const { taskId } = event;

  const task = await getTaskById(taskId);
  return task;
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

خودشه! توابع مرحله بقیه را اداره می کند!

4. خلاصه

ما می توانیم به جای ایجاد معماری های پیچیده و نوشتن کدهای خوانا، مدیریت خطا را به توابع Step واگذار کنیم.

را Retry فیلد مشخص می‌کند که چگونه می‌خواهیم توابع Step در صورت بروز خطا در وضعیت، تلاش‌های مجدد را انجام دهند.

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

5. مطالعه بیشتر

مدیریت خطا در توابع مرحله – States.TaskFailed همه خطاها را پوشش نمی دهد، در اینجا استثناها همراه با سایر گزینه ها وجود دارد

فراخوانی Lambda با توابع Step – عنوان همه چیز را نشان می دهد

تماس با آمازون SNS با توابع مرحله – نحوه پیکربندی توابع مرحله برای انتشار پیام ها به موضوعات

نوشته های مشابه

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

همچنین ببینید
بستن
دکمه بازگشت به بالا