首頁  >  文章  >  後端開發  >  golang進程自己消失

golang進程自己消失

PHPz
PHPz原創
2023-05-10 10:14:06796瀏覽

最近在使用 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中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn