golang學習筆記 優雅的退出golang服務2

2021-10-02 01:56:20 字數 3715 閱讀 8273

前不久介紹了如何比較 優雅的退出golang服務 ,雖然能夠優雅的退出,但是只是簡單的監聽了系統的訊號,後續服務模組得到資源釋放又牽扯到更多的邏輯。對於服務啟動的子協程的宣告週期顯然沒有考慮到。經過一些時間的實踐和閱讀大佬們的**,對如何優雅的退出golang服務再做乙個簡單的記錄。

乙個供外部呼叫的釋放資源的函式,比如:close

chexit:是乙個緩衝區為1的channal。用來接收close介面函式的指令,控制模組的業務邏輯退出。

wg:是sync.waitgroup型別的物件,當模組收到退出訊號後,需要等待已經載入到資料處理快取的資料處理完之後才能退出模組,防止資料丟失的問題。

這個示例中用到了生產-消費的典型模型,消費者和生產者之間使用channel膠合。當主程式收到退信訊號時,主服務呼叫模組serviceclose函式,在close函式中按邏輯釋放service的資源。

1.3.1service的定義

servicec中定義了乙個chexit的channel,並且初始化緩衝區為1。chval是生產者和消費者的膠合channel,wg是保證消費者和生產者的資料能夠同步,保證在退出時不會丟資料。

go s.fetch()模擬生產者,在這個函式中會迴圈往chval中寫入資料,為了模擬退出時的等待,在每次寫資料前會sleep(10s)的時間,這樣在後面觀察時比較明顯。

go s.run()模擬消費者,在這個函式中會從chval中一致取資料,並且將取出的資料列印

type service struct

wg *sync.waitgroup

chval chan

int64

}func

new(

)*service ,1

),wg:

new(sync.waitgroup)

, chval:

make

(chan

int64

,100),

} s.wg.

add(1)

go s.

fetch()

s.wg.

add(1)

go s.

run(

)return s

}

1.3.2 必須的介面

service需要實現close函式,用於在主程式檢測到退出的signal時呼叫,釋放service的資源。

func

(s *service)

close()

error

1.3.3 其他的函式

1.3.4 執行的結果

程式啟動後,生產者和消費者都開始工作。收到退出的訊號後,服務一直等到模擬生產的sleep結束後才退出,保證生產的資料和消費的資料都能夠正常的完成處理。

先簡單寫乙個基於gin的http服務,在這個服務中給請求返回乙個hello world的字串,並且為了後面方便檢視問題,在返回響應之前sleep(10s)的時間。

當頁面或者rest客戶端請求該uri時,rest的service收到了退出的訊號,service開始逐步的釋放資源。此時對http的service執行了硬關閉,對於未處理完的任務會出現不可預見得到錯誤,我們希望在退出時能夠對未處理完的任務正常返回且做一些服務中斷前的必要的操作,防止資源洩露。

2.2.1 **示例

在這個示例中,定義了gin預設的router後直接開始在位址4400上監聽。

func

main()

}() utils.

handlerexit

(func

(s os.signal)

int)

}func

handleroot

() gin.handlerfunc

}

2.2.2 異常的問題

啟動後台服務,正常的情況下,在瀏覽器中請求http://localhost:4400,等待10s後會列印hello world的字樣。但是現在在頁面請求之後,後台程式退出的情況下,並不是預期的,正常的返回資料。頁面返回的結果,如下圖:

2.2.3 正確的方法

利用go的net/http包來監聽位址,並且儲存監聽後返回的srv控制代碼。在收到signal的退出訊號後,再呼叫srv的關閉函式,正常關閉服務。

2.3.5 執行的結果

當頁面正在請求資料時,後台收到了停止指令,srv會等待所有的請求資料返回後再退出。

在多個模組的情況下,將上述兩種柔和到一起就可以完全實現程式的優雅的退出。

在第一節業務處理服務以乙個生產者和乙個消費者的形式做了示例,在乙個生產者和消費者的情況下這麼寫是沒有問題的。但是當存在多個生產者時在退出服務時會發生異常。報錯:panic: send on closed channel,panic: close of closed channel。這是因為在生產者多個生產者時,生產者1退出時關閉了chval,生產者2在等待結束後寫資料時向已經關閉的channel上寫了資料,導致錯發生。

究其原因,我們是在沒有等生產者全部退出後再關閉chval,導致崩潰的發生。下面分別就這個核心問題提出幾個解決方案。

3.2.1 多個waitgroup

利用waitgroup的wait特性,給生產者和消費者定義各自的變數,等待生產者全部退出後再關閉channel,這樣就不會有上述的報錯了。

分別定義多個waitgroup

type service struct

cwg *sync.waitgroup // 消費者的waitgroup

pwg *sync.waitgroup // 生產者的waitgroup

chval chan

int64

}

啟動多個生產者(消費者同理)

var i int64=0

for i =

0; i <

2; i++

s.pwg.

add(1)

go s.

run(

)

close函式中等待生產者全部退出後再關閉chval的channel

func

(s *service)

close()

error

這樣是可以解決這個問題的,執行結果如下:

3.2.2 還有啥辦法啊

golang學習筆記 優雅的退出golang服務

寫了一段時間的golang後台,怎麼優雅的退出程式一直是乙個很模糊的問題。思路還是之前的思路,各種標誌和變數來回控制,雖然說是能夠滿足需求,但是總感覺那開啟的姿勢不對,下面對優雅的退出golang做乙個小總結,廢話不多說,直接上 主程式 模擬乙個服務物件,函式reload和close分別是過載和退出...

Golang的優雅重啟

更新 2015年4月 florian von bock 已將本文中描述的內容轉換為乙個名為 endless 的優秀go包 如果您有golang http服務,可能需要重新啟動它以公升級二進位制檔案或更改某些配置。如果你 像我一樣 因為網路伺服器處理它而優雅地重新啟動是理所當然的,你可能會發現這個配方...

如何優雅的入門golang

golang標準庫文件 高效能分布式系統開發 海量並行處理 遊戲服務端開發再好不過了 package main import fmt func main 複製 go run main.go hello world 複製 識別符號用來命名變數 型別等程式體。乙個或者多個字母 a za z 數字 0 9...