我正在尝试处理与MongoDB的重新连接。为此,我尝试执行三次每个操作(如果它与io.EOF失败)
type MongoDB struct {
session *mgo.Session
DB *mgo.Database
}
func (d MongoDB) performWithReconnect(collection string,
operation func(*mgo.Collection) error) error {
var err error
for i := 0; i < 3; i++ {
session := d.session.Copy()
defer session.Close()
err = operation(session.DB(Config.MongoDb).C(collection))
if err == io.EOF{
continue
}
if err == nil{
return err
}
}
return err
}
所以问题是推迟。它会像我想的那样关闭所有会话,还是会以其他方式表现? 如果你知道一些好的做法来处理这种不同的方式,我将很乐意阅读它们。
答案 0 :(得分:2)
考虑以下program
package main
import (
"fmt"
)
func print(s string, i int) {
fmt.Println(s, i)
}
func main() {
for i := 0; i < 3; i++ {
defer print("loop", i)
}
fmt.Println("after loop 1")
for i := 0; i < 3; i++ {
func(i int) {
defer print("func", i)
}(i)
}
fmt.Println("after loop 2")
}
会打印
after loop 1
func 0
func 1
func 2
after loop 2
loop 2
loop 1
loop 0
延迟函数调用将被置于堆栈中,然后在周围函数结束时以相反的顺序执行。在你的情况下,它会非常糟糕,因为你将有等待关闭的连接。
我建议将循环内容包装到内联函数中。它将根据您的需要调用延迟函数。
答案 1 :(得分:1)
来自A Tour of Go:
延迟语句推迟执行函数,直到周围的函数返回。
因此,在您的代码中,您将创建三个(相同的)延迟函数,这些函数将在函数退出时运行。
如果你需要defer
在循环内运行,你必须把它放在一个函数内。这可以在匿名函数中完成:
for i := 0; i < 3; i++ {
err := func() error {
session := d.session.Copy()
defer session.Close()
return operation(session.DB(Config.MongoDb).C(collection))
}()
if err == io.EOF {
continue
}
if err != nil {
return err
}
}