۰
باید سیستمهای خود را طوری طراحی کنید که به صورت مسالمتآمیز از کار بیفتند.
— مارتین فاولر
سرویس Go شما در حال پردازش هزاران درخواست در دقیقه است. سپس یک بروزرسانی روی سیستم اجرا میشود. سیگنال SIGTERM صادر میشود. چه اتفاقی میافتد؟
اگر پاسخ شما این است که «فقط سرویس خاموش میشود...» — در این صورت ریسک از دست رفتن کارها، دادههای ازدسترفته و کاربران ناراضی را دارید.
خاموشسازی کنترلشده تضمین میکند که سرویس شما به شکل ایمن خارج شود — درخواستهای فعال را کامل کند، منابع را آزاد کند و از آسیب به دادهها جلوگیری کند.
در این راهنمای کوتاه، یاد میگیرید چطور:
تا پایان، سرویس شما فقط خاموش نمیشود —
بلکه مثل یک حرفهای خاموش خواهد شد.
یک خاموشسازی کنترلشده توقف تمیز و کنترل شده سرویس شما است.
مثال: یک کاربر در حال ارسال پرداخت است. در همین لحظه، اپ شما سیگنال خاموشی دریافت میکند. اگر به درستی مدیریت نشود، ممکن است تراکنش از دست برود.
بدون خاموشسازی کنترلشده:
با خاموشسازی کنترلشده:
1func main() { 2 http.ListenAndServe(":8080", handler) // بلاک میشود برای همیشه 3}
بسیاری از برنامهها هنگام دریافت سیگنال خاموشی کاری انجام نمیدهند. در نتیجه فرایند بلافاصله خارج میشود، بدون هیچ تمیزکاری یا بازیابی.
1ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM) 2defer stop()
سپس با استفاده از server.Shutdown(ctx) اجازه میدهید درخواستها تکمیل شوند، پایگاه داده بسته شود و کارگران متوقف گردند.
بسته شدن یک رستوران:
سرویسها هم همینطورند: خراب نشوید — درست بسته شوید.
1ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM) 2defer stop()
این یک context.Context برمیگرداند که هنگام دریافت SIGINT یا SIGTERM کنسل میشود.
1server := &http.Server{Addr: ":8080", Handler: yourHandler} 2 3 4go func() { 5 if err := server.ListenAndServe(); err != http.ErrServerClosed { 6 log.Fatalf("Server error: %v", err) 7 } 8}()
به این ترتیب گوروتین اصلی آزاد میماند تا سیگنال خاموشی را مدیریت کند.
1<-ctx.Done() 2log.Println("Shutdown signal received")
این خط برنامه را بلاک میکند تا وقتی سیگنال خاموشی دریافت شود.
1shutdownCtx, cancel := context.WithTimeout(context.Background(), 10*time.Second) 2defer cancel() 3 4 5if err := server.Shutdown(shutdownCtx); err != nil { 6 log.Printf("Graceful shutdown failed: %v", err) 7} else { 8 log.Println("Server shut down cleanly") 9}
این اطمینان میدهد همه درخواستها یا تکمیل شوند یا پس از ۱۰ ثانیه تایماوت شود.
بسیاری از برنامههای Go از goroutineهای پسزمینه برای پردازش کارها، دریافت پیامها یا انجام کارهای دورهای استفاده میکنند. اگر اینها به درستی متوقف نشوند، ممکن است:
۱. استفاده از Context در کارگران
یک context.Context به هر کارگر پاس بدهید و منتظر لغو آن بمانید:
1func startWorker(ctx context.Context, jobs <-chan Job) { 2 for { 3 select { 4 case <-ctx.Done(): 5 log.Println("Worker received shutdown signal") 6 return 7 case job := <-jobs: 8 process(job) 9 } 10 } 11}
۲. اجرای کارگران با WaitGroup
1var wg sync.WaitGroup 2wg.Add(1) 3go func() { 4 defer wg.Done() 5 startWorker(ctx, jobQueue) 6}()
۳. صبر کردن پیش از خروج
بعد از فراخوانی cancel() روی context خاموشی، منتظر بمانید تا همه کارگران کارشان را تمام کنند:
1stop() // لغو signal.NotifyContext 2wg.Wait() // انتظار برای اتمام همه کارگران
با این الگو:
Kubernetes به سرعت پاد (Pod) شما را نمیکشد. فرصتی به برنامه میدهد تا بتواند خاموش شود، البته اگر بلد باشید چطور استفاده کنید.
مراحل در زمان پایان پاد:
۱. به کانتینر شما SIGTERM ارسال میشود
۲. پروب Readiness شکست میخورد و ترافیک ورودی قطع میشود
۳. شما مدت زمان terminationGracePeriodSeconds (به طور پیشفرض ۳۰ ثانیه) برای خاموش شدن دارید
۴. اگر به موقع خاموش نشدید، Kubernetes سیگنال SIGKILL ارسال میکند
signal.NotifyContext استفاده کنید تا اپ به SIGTERM واکنش دهدserver.Shutdown() تنظیم کنیدمثالی از پروب readiness که هنگام خاموش شدن با شکست مواجه میشود:
1var ready = true 2 3http.HandleFunc("/healthz", func(w http.ResponseWriter, r *http.Request) { 4 if !ready { 5 http.Error(w, "shutting down", http.StatusServiceUnavailable) 6 return 7 } 8 w.Write([]byte("ok")) 9}) 10 11// هنگام دریافت SIGTERM: 12ready = false // پروب readiness شروع به شکست خوردن میکند
SIGKILL دریافت میکندos.Exit: که باعث میشود پاکسازی انجام نشودکubernetes ابزار لازم را در اختیار شما میگذارد، اما اپ شما باید به درستی واکنش نشان دهد.
خاموشسازی کنترلشده فقط یک الگو نیست — یک انضباط است.
کد واکنشی را به سیستمهای قابل اطمینان تبدیل میکند.
چه در Kubernetes اجرا کنید، چه روی سرور اختصاصی یا محیطهای بدون سرور (serverless)، همیشه سرویسها را طوری طراحی کنید که به شکل تمیز از صحنه خارج شوند.
چون وقتی به درستی انجام شود، هیچ کاربری متوجه نمیشود — و این نقطه اصلی موضوع است.
۰
کد با می متعهد است که بالاترین سطح کیفی آموزش را در اختیار شما بگذارد. هدف به اشتراک گذاشتن دانش فناوری اطلاعات و توسعه نرم افزار در بالاترین سطح ممکن برای درستیابی به جامعه ای توانمند و قدرتمند است. ما باور داریم هر کسی میتواند با استمرار در یادگیری برنامه نویسی چالش های خود و جهان پیرامون خود را بر طرف کند و به موفقیت های چشم گیر برسد. با ما در این مسیر همراه باشید. کد با می اجتماع حرفه ای برنامه نویسان ایرانی.