亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

有什么辦法可以阻止默認的golang程序完成

有什么辦法可以阻止默認的golang程序完成

Go
繁花如伊 2023-07-26 10:07:36
我有一個使用 websocket 連接和數據庫的服務器。有些用戶可以通過套接字連接,所以我需要在db中增加他們的“在線”;在他們斷開連接的那一刻,我還減少了他們在數據庫中的“在線”字段。但為了防止服務器崩潰,我使用在線用戶的本地變量副本map[string]int。因此,我需要推遲服務器關閉,直到它完成一個數據庫請求,該請求根據我的變量副本減少所有“在線”用戶,因為這樣套接字連接不會發送默認的“關閉”事件。我找到了一個包 github.com/xlab/closer ,它可以處理一些系統調用,并且可以在程序完成之前執行一些操作,但我的數據庫請求不能以這種方式工作(代碼如下)func main() {  ...  // trying to handle program finish event  closer.Bind(cleanupSocketConnections(&pageHandler))  ...}// function that handles program finish eventfunc cleanupSocketConnections(p *controllers.PageHandler) func() {    return func() {        p.PageService.ResetOnlineUsers()    }}// this map[string]int contains key=userId, value=count of socket connectionstype PageService struct {    Users map[string]int}func (p *PageService) ResetOnlineUsers() {    for userId, count := range p.Users {        // decrease online of every user in program variable        InfoService{}.DecreaseInfoOnline(userId, count)    }}也許我使用不正確,或者可能有更好的方法來防止默認程序完成?
查看完整描述

2 回答

?
ibeautiful

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

}



查看完整回答
反對 回復 2023-07-26
?
慕哥9229398

TA貢獻1877條經驗 獲得超6個贊

我認為你需要看看goroutineChannel

查看完整回答
反對 回復 2023-07-26
  • 2 回答
  • 0 關注
  • 160 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號