最近在使用 Golang 寫的程式中遇到了一個很奇怪的問題,就是進程自己消失了。在經過一番排查之後,我發現了問題,並總結了一些經驗。下面就來分享我遇到的問題和解決方案。
我們的產品在每天定時執行一次任務,在最近的幾天中,我發現任務總是在幾分鐘後停止了,我設定了進程的log 輸出到檔案中,然後查看log 才發現進程只運行了幾分鐘就自己消失了。這種情況非常奇怪,因為在平常的開發和測試中,我都沒有遇到類似的問題。
首先,我想到了一個最簡單的解決方法:在程式碼中加入 debug 資訊。於是,我在進程啟動的時候,輸出了一條 start
的 log,然後每執行一些重要的操作,再輸出一條對應的 log。然後,我重新啟動了任務,等待它停止,然後查看 log,發現進程剛啟動了幾分鐘就停止了,但是它在 log 中沒有輸出任何錯誤訊息,似乎它就是自己終止了。
接著,我嘗試使用 strace
命令來追蹤進程的系統調用,看看它終止的原因。但是,這個進程的結構比較複雜,有多個 goroutine 在運作。我使用了 strace
指令來追蹤其中的一個 goroutine(ndeliver),看看它的系統呼叫情況。以下是ndeliver
goroutine 的相關程式碼:
c := make(chan os.Signal, 1) signal.Notify(c, syscall.SIGINT, syscall.SIGTERM) go func() { sig := <-c log.Errorf("main: received signal %s, shutting down server", sig.String()) server.Stop() os.Exit(0) }() go func() { err := server.Start() if err != nil { log.Fatalf("ndeliver: server start error: %s", err) } }()
這段程式碼的作用是為進程註冊訊號處理函數,並啟動一個goroutine 來執行server.Start()
函數,函數會一直阻塞直到進程退出。
透過 strace
指令,我發現這個 goroutine 沒有任何異常,它也沒有遇到什麼錯誤就退出了。但是,我發現進程中還有其他的goroutine,我繼續使用strace
命令來追蹤其中一個goroutine,然後,我發現了問題,一個goroutine 拋出了一個panic,而且這個panic 沒有被處理,於是整個進程就崩潰了。
透過查看程式碼,我發現這個 panic 是因為一個檔案被刪除而引起的,但是我們的程式碼並沒有處理這個錯誤。當一個 goroutine 的 panic 沒有被處理時,整個進程就會崩潰,這就是為什麼進程自己消失了。
為了解決這個問題,我們需要對 panic 進行處理,避免它崩潰整個進程。我們可以在需要的地方使用 recover 函數來捕捉 panic,然後處理它,避免進程崩潰。
下面是處理panic 的程式碼範例:
defer func() { if r := recover(); r != nil { log.Errorf("goroutine panic: %v", r) // TODO: 处理 panic } }() // 代码片段
透過使用defer 函數,在goroutine 終止時,即使它發生了panic,我們也可以捕捉它並進行相應的處理,在這裡我們只是簡單地輸出了panic 的信息,但是實際上,我們還可以在這裡做其他的處理,例如發送警報或記錄有關錯誤的更多信息。
在編寫 Golang 程式碼時,由於 goroutine 的特別性質,當一個 goroutine 發生 panic 時,它可能會導致整個進程崩潰。因此,在編寫程式碼時,我們必須考慮到這種情況,並編寫程式碼來處理這種情況。在程式碼中加入 panic 處理非常重要,它可以幫助我們避免在生產環境中遇到類似的問題。
以上是golang進程自己消失的詳細內容。更多資訊請關注PHP中文網其他相關文章!