我目前在我的应用中使用RethinkDB
,因为他们的实时事件驱动数据。我目前有这个监视功能,可以检查在线用户:
func (c *connection) watchUsers() {
db := common.DB()
query := gorethink.Table("Users").Filter(map[string]interface{}{
"online": 1,
}).Changes(gorethink.ChangesOpts{
IncludeInitial: true,
})
res, err := query.Run(db)
if err != nil {
log.Println(err)
}
defer res.Close()
var users interface{}
for res.Next(&users) {
if c.disconnecting {
break
}
usersNewMap := users.(map[string]interface{})["new_val"]
user := usersNewMap.(map[string]interface{})
log.Println(user["username"])
c.ws.WriteJSON(wsMsg{
"user add",
map[string]interface{}{
"username": user["username"].(string),
"uuid": user["id"].(string),
},
})
}
log.Println("Ended on disconnect")
}
唯一的问题是我需要在websocket断开连接时返回watchUsers
函数。现在我有
defer func() {
c.disconnecting = true
}()
在websocket中,当手表试图在另一个公告上获得更多数据时,它会打破循环并结束goroutine。唯一的问题是,如果没有数据要播放一段时间,现在这个goroutine暂停一段时间占用不必要的空间。所以我的问题是,我怎么能用某种事件驱动的方法打破这个循环,如果我可以让res.Next
成为一个通道会更容易因为那时我可以使用一个选择,但事实并非如此
答案 0 :(得分:0)
所以我提出了一个解决方案,使用来自@CodingPickle的建议似乎工作得很好,简而言之,在自己的goroutine中运行for循环,然后在完成观看时执行res.Close()
。
func (c *connection) watchUsers() {
db := common.DB()
query := gorethink.Table("Users").Filter(map[string]interface{}{
"online": 1,
}).Changes(gorethink.ChangesOpts{
IncludeInitial: true,
})
res, err := query.Run(db)
if err != nil {
log.Println(err)
}
go func(res *gorethink.Cursor, c *connection) {
defer res.Close()
var users interface{}
for res.Next(&users) {
usersNewMap := users.(map[string]interface{})["new_val"]
user := usersNewMap.(map[string]interface{})
c.send <- wsMsg{
"user add",
map[string]interface{}{
"username": user["username"].(string),
"uuid": user["id"].(string),
},
}
}
log.Println("Ended gracefully")
}(res, c)
select {
case <-c.disconnecting:
res.Close()
break
case <-c.stopWatchingUsers:
res.Close()
break
}
}