2 回答

TA貢獻1993條經驗 獲得超6個贊
首先,正如您所說,當服務器“崩潰”時執行任務是相當復雜的,因為崩潰可能意味著很多事情,并且當服務器中出現嚴重問題時,沒有什么可以保證清理功能的執行。
從工程角度來看(如果在故障時將用戶設置為離線如此重要),最好是在另一臺服務器上有一個輔助服務,該服務接收用戶連接和斷開連接事件以及 ping 事件(如果它在某個時間段內沒有收到任何更新)設置超時該服務會認為您的服務器已關閉并繼續將每個用戶設置為離線。
回到你的問題,使用 defer 和等待終止信號應該覆蓋 99% 的情況。我對代碼進行了注釋以解釋邏輯。
// AllUsersOffline is called when the program is terminated, it takes a *sync.Once to make sure this function is performed only
// one time, since it might be called from different goroutines.
func AllUsersOffline(once *sync.Once) {
once.Do(func() {
fmt.Print("setting all users offline...")
// logic to set all users offline
})
}
// CatchSigs catches termination signals and executes f function at the end
func CatchSigs(f func()) {
cSig := make(chan os.Signal, 1)
// watch for these signals
signal.Notify(cSig, syscall.SIGKILL, syscall.SIGTERM, syscall.SIGINT, syscall.SIGQUIT, syscall.SIGHUP) // these are the termination signals in GNU => https://www.gnu.org/software/libc/manual/html_node/Termination-Signals.html
// wait for them
sig := <- cSig
fmt.Printf("received signal: %s", sig)
// execute f
f()
}
func main() {
/* code */
// the once is used to make sure AllUsersOffline is performed ONE TIME.
usersOfflineOnce := &sync.Once{}
// catch termination signals
go CatchSigs(func() {
// when a termination signal is caught execute AllUsersOffline function
AllUsersOffline(usersOfflineOnce)
})
// deferred functions are called even in case of panic events, although execution is not to take for granted (OOM errors etc)
defer AllUsersOffline(usersOfflineOnce)
/* code */
// run server
err := server.Run()
if err != nil {
// error logic here
}
// bla bla bla
}
- 2 回答
- 0 關注
- 160 瀏覽
添加回答
舉報