为了账号安全,请及时绑定邮箱和手机立即绑定

有什么办法可以阻止默认的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条经验 获得超5个赞

首先,正如您所说,当服务器“崩溃”时执行任务是相当复杂的,因为崩溃可能意味着很多事情,并且当服务器中出现严重问题时,没有什么可以保证清理功能的执行。


从工程角度来看(如果在故障时将用户设置为离线如此重要),最好是在另一台服务器上有一个辅助服务,该服务接收用户连接和断开连接事件以及 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 关注
  • 114 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信