استخدام `recover`
جزء من قسم Logic & Flow في رحلة GO على Coddy — الدرس 43 من 68.
بينما يوقف panic برنامجك فوراً، توفر Go طريقة لاستعادة السيطرة من خلال الدالة recover. تسمح الدالة recover لك بالتقاط panic والتعامل معه بسلاسة، مما يمنع برنامجك بالكامل من الانهيار.
ومع ذلك، فإن recover لديه متطلب محدد للغاية: لا يمكن استخدامه إلا داخل دالة مؤجلة (deferred function). فعند حدوث panic، تقوم Go بتنفيذ جميع الدوال المؤجلة قبل انتهاء البرنامج، مما يمنح recover فرصة لاعتراض الـ panic:
func riskyFunction() {
defer func() {
if r := recover(); r != nil {
fmt.Println("Recovered from panic:", r)
}
}()
panic("something went wrong!")
}تعيد الدالة recover القيمة التي تم تمريرها إلى panic، أو nil إذا لم يحدث panic. يتيح لك ذلك التحقق مما إذا كان قد حدث panic واتخاذ الإجراء المناسب، مثل تسجيل الخطأ أو إجراء عمليات التنظيف.
مثل panic، يجب استخدام recover بحذر في Go. يُشاهد هذا بشكل شائع في سيناريوهات مثل خوادم الويب حيث تريد منع حدوث panic في طلب واحد من التسبب في تعطل الخادم بالكامل، مما يسمح له بالاستمرار في خدمة الطلبات الأخرى.
يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.
يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.
يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.
التحدي
سهلقم ببناء معالج طلبات لخادم ويب يستخدم recover للتعامل بلباقة مع حالات الـ panic ومنع الخادم بأكمله من الانهيار. يوضح هذا التحدي كيفية استخدام recover داخل دالة مؤجلة (deferred function) لالتقاط حالات الـ panic والحفاظ على استقرار الخادم.
ستتلقى مدخلين:
- سلسلة نصية تحتوي على تفاصيل الطلب بتنسيق
"endpoint,method,action"(على سبيل المثال،"/api/users,GET,process") - سلسلة نصية تحتوي على إعدادات الخادم بتنسيق
"server_name,max_requests"(على سبيل المثال،"WebServer,100")
مهمتك هي:
- تحليل المدخل الأول عن طريق تقسيمه بناءً على الفواصل للحصول على endpoint و method و action
- تحليل المدخل الثاني عن طريق تقسيمه بناءً على الفواصل للحصول على server name و max requests
- تحويل سلسلة max requests النصية إلى عدد صحيح (integer)
- إنشاء دالة تسمى
handleRequestتأخذ endpoint و method و action و server name كمعاملات - داخل
handleRequest، أضف دالة مؤجلة (deferred function) تستخدمrecoverلالتقاط أي panic:- إذا تم استرداد panic (عندما تعيد recover قيمة غير فارغة)، اطبع:
"Server [server_name] recovered from panic: [panic_value]" - بعد التعامل مع الـ panic، اطبع:
"Request handling completed safely"
- إذا تم استرداد panic (عندما تعيد recover قيمة غير فارغة)، اطبع:
- بعد الدالة المؤجلة، قم بمحاكاة معالجة الطلب بناءً على الـ action:
- إذا كان action هو
"process": اطبع"Processing [method] request to [endpoint]" - إذا كان action هو
"panic_nil": اطبع"Attempting dangerous operation"ثم استدعِpanic("nil pointer access") - إذا كان action هو
"panic_overflow": اطبع"Attempting resource allocation"ثم استدعِpanic("memory overflow") - إذا كان action هو
"panic_timeout": اطبع"Attempting database connection"ثم استدعِpanic("connection timeout") - لأي action آخر: اطبع
"Unknown action: [action]"ثم استدعِpanic("invalid action")
- إذا كان action هو
- في الدالة الرئيسية (main function)، اطبع رسالة بدء تشغيل الخادم:
"Starting [server_name] with max [max_requests] requests" - استدعِ دالة
handleRequestمع المعاملات التي تم تحليلها - بعد استدعاء الدالة، اطبع حالة الخادم:
"Server [server_name] is still running" - أخيرًا، اطبع ملخصًا:
"Server Summary:""Name: [server_name]""Max Requests: [max_requests]""Last Request: [method] [endpoint]""Action Performed: [action]""Status: Operational"
استخدم حزمة strings لتقسيم سلاسل المدخلات بناءً على الفواصل وحزمة strconv لتحويل سلسلة max requests النصية إلى عدد صحيح. يوضح هذا التحدي كيف تسمح recover للخوادم بالتعامل مع حالات الـ panic غير المتوقعة بلباقة، مما يمنع فشل الطلبات الفردية من إسقاط النظام بأكمله.
ورقة مرجعية
تتيح لك الدالة recover التقاط الـ panic ومعالجته بلباقة، مما يمنع برنامجك من الانهيار.
لا يمكن استخدام recover إلا داخل دالة مؤجلة (deferred function):
func riskyFunction() {
defer func() {
if r := recover(); r != nil {
fmt.Println("Recovered from panic:", r)
}
}()
panic("something went wrong!")
}تعيد الدالة recover القيمة التي تم تمريرها إلى panic، أو nil في حال لم يحدث panic. يتيح لك ذلك التحقق مما إذا كان قد حدث panic واتخاذ الإجراء المناسب.
تُستخدم recover بشكل شائع في خوادم الويب لمنع الـ panic الخاص بطلب واحد من التسبب في انهيار الخادم بأكمله.
جرّب بنفسك
package main
import (
"fmt"
"strconv"
"strings"
)
func main() {
// قراءة المدخلات
var requestDetails string
var serverConfig string
fmt.Scanln(&requestDetails)
fmt.Scanln(&serverConfig)
// تحليل تفاصيل الطلب
requestParts := strings.Split(requestDetails, ",")
endpoint := requestParts[0]
method := requestParts[1]
action := requestParts[2]
// تحليل إعدادات الخادم
configParts := strings.Split(serverConfig, ",")
serverName := configParts[0]
maxRequests, _ := strconv.Atoi(configParts[1])
// TODO: اكتب الكود الخاص بك أدناه
// إنشاء دالة handleRequest مع آلية الاسترداد (recover)
// طباعة رسالة بدء تشغيل الخادم
// استدعاء دالة handleRequest
// طباعة حالة الخادم والملخص
}يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.
جميع دروس Logic & Flow
1تدفق التحكم المتقدم
جملة Switch مع `fallthrough`الخروج من الحلقات المتداخلةالاستمرار في حلقة محددةجملة `goto`ملخص - التحكم المتقدم في الحلقات7معالجة الأخطاء بعمق
أنواع الأخطاء المخصصةتغليف الأخطاء باستخدام `%w`فك التغليف باستخدام `errors.Is`فك التغليف باستخدام `errors.As`فهم `panic`استخدام `recover`ملخص - القسمة الآمنة2الـ Structs والميثودز (Methods)
تعريف الـ Methods على الـ Structsالـ Value Receiversالـ Pointer Receiversاختيار الـ Receiversالـ Methods مقابل الـ Functionsملخص - سلوك الـ Struct5تعمق في الـ Maps
Maps من نوع Structsالـ Pointers كقيم في الـ Mapsالتحقق من الـ Nil Mapsمقارنة الـ Mapsمراجعة - عداد تكرار الكلمات3الواجهات (الأساسيات)
ما هي الواجهة؟تعريف الواجهةتطبيق الواجهةاستخدام أنواع الواجهاتالواجهة الفارغةتأكيدات النوع (Type Assertions)تبديل النوع (Type Switch)ملخص - الأشكال والسلوكيات