猿问

有什么办法可以阻止默认的golang程序完成

我有一个使用 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 event

func cleanupSocketConnections(p *controllers.PageHandler) func() {

    return func() {

        p.PageService.ResetOnlineUsers()

    }

}


// this map[string]int contains key=userId, value=count of socket connections

type 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)

    }

}

也许我使用不正确,或者可能有更好的方法来防止默认程序完成?


繁花如伊
浏览 115回答 2
2回答

ibeautiful

首先,正如您所说,当服务器“崩溃”时执行任务是相当复杂的,因为崩溃可能意味着很多事情,并且当服务器中出现严重问题时,没有什么可以保证清理功能的执行。从工程角度来看(如果在故障时将用户设置为离线如此重要),最好是在另一台服务器上有一个辅助服务,该服务接收用户连接和断开连接事件以及 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) {&nbsp; &nbsp; once.Do(func() {&nbsp; &nbsp; &nbsp; &nbsp; fmt.Print("setting all users offline...")&nbsp; &nbsp; &nbsp; &nbsp; // logic to set all users offline&nbsp; &nbsp; })}// CatchSigs catches termination signals and executes f function at the endfunc CatchSigs(f func()) {&nbsp; &nbsp; cSig := make(chan os.Signal, 1)&nbsp; &nbsp; // watch for&nbsp; these signals&nbsp; &nbsp; signal.Notify(cSig, syscall.SIGKILL, syscall.SIGTERM, syscall.SIGINT, syscall.SIGQUIT, syscall.SIGHUP) // these are the termination signals in GNU =>&nbsp; https://www.gnu.org/software/libc/manual/html_node/Termination-Signals.html&nbsp; &nbsp; // wait for them&nbsp; &nbsp; sig := <- cSig&nbsp; &nbsp; fmt.Printf("received signal: %s", sig)&nbsp; &nbsp; // execute f&nbsp; &nbsp; f()}func main() {&nbsp; &nbsp; /* code */&nbsp; &nbsp; // the once is used to make sure AllUsersOffline is performed ONE TIME.&nbsp; &nbsp; usersOfflineOnce := &sync.Once{}&nbsp; &nbsp; // catch termination signals&nbsp; &nbsp; go CatchSigs(func() {&nbsp; &nbsp; &nbsp; &nbsp; // when a termination signal is caught execute AllUsersOffline function&nbsp; &nbsp; &nbsp; &nbsp; AllUsersOffline(usersOfflineOnce)&nbsp; &nbsp; })&nbsp; &nbsp; // deferred functions are called even in case of panic events, although execution is not to take for granted (OOM errors etc)&nbsp; &nbsp; defer AllUsersOffline(usersOfflineOnce)&nbsp; &nbsp; /* code */&nbsp; &nbsp; // run server&nbsp; &nbsp; err := server.Run()&nbsp; &nbsp; if err != nil {&nbsp; &nbsp; &nbsp; &nbsp; // error logic here&nbsp; &nbsp; }&nbsp; &nbsp; // bla bla bla}

慕哥9229398

我认为你需要看看goroutine和Channel。
随时随地看视频慕课网APP

相关分类

Go
我要回答