Handle Unhandled Exceptions مدیریت خطاهای مدیریت نشده

خطاهای 500 یا سرور نرم افزار شما چگونه به کاربر می رسند؟ آیا مدیریت می شوند؟ کاربر چگونه این خطاها را به مسئول سیستم شما گزارش می کند؟ آیا مسئول سیستم و توسعه دهندگان به راحتی می توانند مشکل تشخیص دهند و آن را برطرف کنند؟


پیاده سازی و ساخت Back-end یک نرم افزار و ایجاد API هایی برای سرویس دهی به سایر برنامه ها شامل در نظر گرفتن جنبه های مختلفی می باشد، از جمله:

  • معماری و طرح کلی نرم افزار Architecture and Design Patterns
  • ارتباط با دیتابیس Persistence Layer
  • بیزینس لاجیک Business Logic
  • امنیت نرم افزار، احراز هویت و احراز دسترسی Authentication & Authorization
  • ارتباط با سایر سرویس ها
  • ارتباط با فایل
  • ایجاد API ها
  • مانیتورینگ و بررسی سلامت نرم افزار Monitoring & Health Checks
  • تست های اتوماتیک
  • بیلد و نسخه گذاری اتوماتیک CI/CD
  • کارایی نرم افزار Performance
  • مدیریت تراکنش ها Transaction Management
  • جاب ها Job Scheduling
  • وب سوکت WebSocket

و اما مورد بحث این پست:

  • مدیریت خطاها

مدیریت خطاها

فارغ از زبان ها، تکنولوژی ها و کتابخانه های استفاده شده، نهایتا کاربر استفاده کننده از API های ما به خطاهای مختلفی برخورد خواهد کرد، می توان این خطاها رو به چند دسته ی کلی زیر تقسیم بندی کرد:

  • خطاهای بیزینسی؛ به عنوان مثال: موجودی حساب شما کافی نیست.
  • خطاهای استفاده ی نادرست؛ به عنوان مثال: ورودی های API به شکل درست ارسال نمی شوند.
  • خطاهای امنیتی؛ به عنوان مثال: شما به این سرویس دسترسی ندارید.

و اما مورد بحث این پست:

  • خطاهای مدیریت نشده؛ یا خطاهای سرور 5XX

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

معمولا هنگام رخداد این گونه خطاها پیامی از سرور ارسال می شود تا کاربر متوجه شود که خطایی رخ داده است و باید با مسئول یا پشیتبان سیستم تماس بگیرد.

نمونه خطای پیش فرض مرورگر هنگام مواجه با خطای 500
نمونه خطای پیش فرض مرورگر هنگام مواجه با خطای 500

فرض کنید نرم افزار در محیط پروداکشن اجرا شده است و هزاران کاربر همزمان در حال استفاده از آن هستند. کاربری با خطای 500 مواجه می شود و با مسئول سیستم تماس می گیرد و مشکل را گزارش می کند.

ایراد این روش آن است که مسئول سیستم چگونه ایراد را پیدا کند!؟ آن هم بین هزاران خط لاگ برنامه که هر لحظه بر تعداد آن ها افزوده می شود. حتی اگر سطح لاگ برنامه نیز مدیریت شود تا لاگهای با سطح حساسیت بیشتری ثبت شوند، باز هم ممکن است چندین کاربر همزمان به خطاهای 500 مختلف بربخورند و تشخیص و تعیین اینکه چه لاگ خطایی مربوط به چه کاربری بوده امری دشوار می باشد.

پیدا کردن لاگ خطای مورد نظر بین هزاران خط لاگ برنامه یا تعیین لاگ مربوط به خطای گزارش شده بین هزاران لاگ خطا امری بسیار دشوار است.

معرفی روش پیشنهادی

بصورت خلاصه روش پیشنهادی بدین صورت است که در لایه ای از برنامه که خطای مورد نظر به HTTP Response تبدیل می شود، علاوه بر ثبت لاگ خطا، کدی کوتاه و تاحدودی یکتا تولید شود که علاوه بر اینکه همراه خطا لاگ می شود، به عنوان کد رهگیری به کاربر نیز ارسال شود.

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

نمونه پیاده سازی در Spring Boot

در اینجا نمونه ای از چگونگی پیاده سازی این روش پیشنهادی در Spring Boot آورده می شود:

در کلاسی با نام فرضی ApplicationExceptionAdvice که با @ControllerAdvice مشخص شده است تا خطاهای ایجاد شده در برنامه، مدیریت Handle شوند، handler مربوط به خطای کلی Exception ایجاد می شود:

12345678910@ControllerAdvice
public abstract class ApplicationExceptionAdvice  {
    protected final Logger LOGGER = LoggerFactory.getLogger(this.getClass());
    @ExceptionHandler(Exception.class)
    public ResponseEntity<?> handle(Exception ex) {
        int randomTrackingNo = RandomUtils.nextInt(1000, 9999);
        LOGGER.error(&quottrackingNo:{}, {} exception occur: {}&quot, randomTrackingNo, ex.getClass().getSimpleName(), ex);
        return new ResponseEntity(&quotsystem.unHandled.exception: &quot+randomTrackingNo, HttpStatus.INTERNAL_SERVER_ERROR);
    }
}

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

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

لطفا نظر خودتون رو در مورد این روش، یا روش های پیشنهادی خودتون همینجا بیان کنید.