我想知道Go使用mgo中的MongoDB会话管理,尤其是关于如何正确确保会话关闭以及如何对写入失败作出反应。
我已阅读以下内容:
Best practice to maintain a mgo session
Should I copy session for each operation in mgo?
但是,不能适用于我的情况。
我有两个goroutines将事件后事件存储到MongoDB中,共享相同的* mgo.Session,两者看起来都像以下一样:
func storeEvents(session *mgo.Session) {
session_copy := session.Copy()
// *** is it correct to defer the session close here? <-----
defer session_copy.Close()
col := session_copy.DB("DB_NAME").C("COLLECTION_NAME")
for {
event := GetEvent()
err := col.Insert(&event)
if err != nil {
// *** insert FAILED - how to react properly? <-----
session_copy = session.Copy()
defer session_copy.Close()
}
}
}
几小时后col.Insert(&amp; event)返回错误
read tcp 127.0.0.1:46954->127.0.0.1:27017: i/o timeout
我不确定如何对此做出反应。发生此错误后,它会在所有后续写入时发生,因此我似乎必须创建一个新会话。我的替代品似乎是:
1)重启整个goroutine,即
if err != nil {
go storeEvents(session)
return
}
2)创建一个新的会话副本
if err != nil {
session_copy = session.Copy()
defer session_copy.Close()
col := session_copy.DB("DB_NAME").C("COLLECTION_NAME")
continue
}
- &GT;我使用defer session_copy.Close()
的方式是否正确? (注意上面的延迟引用了另一个会话的Close()函数。无论如何,这些会话永远不会被关闭,因为函数永远不会返回。即,随着时间的推移,会创建许多会话而不会关闭。
其他选择?
答案 0 :(得分:0)
所以我不知道这对你有什么帮助,但我对这个设置没有任何问题。
我有一个我从中导入的mongo包。这是我的mongo.go文件的模板
package mongo
import (
"time"
"gopkg.in/mgo.v2"
)
var (
// MyDB ...
MyDB DataStore
)
// create the session before main starts
func init() {
MyDB.ConnectToDB()
}
// DataStore containing a pointer to a mgo session
type DataStore struct {
Session *mgo.Session
}
// ConnectToTagserver is a helper method that connections to pubgears' tagserver
// database
func (ds *DataStore) ConnectToDB() {
mongoDBDialInfo := &mgo.DialInfo{
Addrs: []string{"ip"},
Timeout: 60 * time.Second,
Database: "db",
}
sess, err := mgo.DialWithInfo(mongoDBDialInfo)
if err != nil {
panic(err)
}
sess.SetMode(mgo.Monotonic, true)
MyDB.Session = sess
}
// Close is a helper method that ensures the session is properly terminated
func (ds *DataStore) Close() {
ds.Session.Close()
}
然后在另一个包中,例如主根据以下评论更新
package main
import (
"../models/mongo"
)
func main() {
// Grab the main session which was instantiated in the mongo package init function
sess := mongo.MyDB.Session
// pass that session in
storeEvents(sess)
}
func storeEvents(session *mgo.Session) {
session_copy := session.Copy()
defer session_copy.Close()
// Handle panics in a deferred fuction
// You can turn this into a wrapper (middleware)
// remove this this function, and just wrap your calls with it, using switch cases
// you can handle all types of errors
defer func(session *mgo.Session) {
if err := recover(); err != nil {
fmt.Printf("Mongo insert has caused a panic: %s\n", err)
fmt.Println("Attempting to insert again")
session_copy := session.Copy()
defer session_copy.Close()
col := session_copy.DB("DB_NAME").C("COLLECTION_NAME")
event := GetEvent()
err := col.Insert(&event)
if err != nil {
fmt.Println("Attempting to insert again failed")
return
}
fmt.Println("Attempting to insert again succesful")
}
}(session)
col := session_copy.DB("DB_NAME").C("COLLECTION_NAME")
event := GetEvent()
err := col.Insert(&event)
if err != nil {
panic(err)
}
}
我在AWS上的生产服务器上使用类似的设置。我每小时做100多万次插入。希望这可以帮助。我为确保mongo服务器可以处理连接而做的另一件事是增加了我的生产机器上的ulimit。它在stack
中进行了讨论