mongodb - golang - mgo collection
Las mejores prácticas para mantener una sesión mgo (3)
Aunque no responde directamente a su pregunta, con respecto a la comprobación de la sesión mgo debe usar diferir / recuperar ya que las llamadas mgo (incluso mgo.session.Ping) entran en pánico.
Por lo que puedo decir, no hay otra forma de verificar el estado de la sesión
mgo
(
mgo godocs
).
Puede usar la sugerencia de
Gustavo Niemeyer
y agregar un método en su tipo de
DataStore
.
func (d *DataStore) EnsureConnected() {
defer func() {
if r := recover(); r != nil {
//Your reconnect logic here.
}
}()
//Ping panics if session is closed. (see mgo.Session.Panic())
d.Ping()
}
Actualmente estoy usando un mongodb con mgo lib para una aplicación web, pero no estoy seguro de si la forma en que lo estoy usando es buena.
package db
import (
"gopkg.in/mgo.v2"
)
const (
MongoServerAddr = "192.168.0.104"
RedisServerAddr = "192.168.0.104"
)
var (
MongoSession, err = mgo.Dial(MongoServerAddr)
MDB = MongoSession.DB("message")
MCol = MDB.C("new")
MSav = MDB.C("save")
UDB = MongoSession.DB("account")
UCol = UDB.C("user")
)
Inicio la sesión de db y creo variables que toman la colección y el valor del documento, así que cuando necesito consultar una colección, uso la variable para hacerla.
Como eso :
func UserExist(username string) bool {
user := Users{}
err := db.UCol.Find(bson.M{"username": username}).One(&user)
if err != nil {
return false
} else {
return true
}
}
Entonces, ¿hay una mejor práctica o esta está bien? Gracias
Con go 1.7, la forma más idiomática de manejar la sesión de mongo en un servidor web es usar el nuevo
context
paquete de biblioteca estándar para escribir un middleware que pueda adjuntar la
defer session.Close()
.
Por lo tanto, no necesita recordar para cerrar
AttachDeviceCollection = func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
db, err := infra.Cloner()
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
collection, err := NewDeviceCollection(db)
if err != nil {
db.Session.Close()
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
ctx := context.WithValue(r.Context(), DeviceRepoKey, collection)
go func() {
select {
case <-ctx.Done():
collection.Session.Close()
}
}()
next.ServeHTTP(w, r.WithContext(ctx))
})
}
Sugiero no usar una sesión global como esa. En su lugar, puede crear un tipo que sea responsable de toda la interacción de la base de datos. Por ejemplo:
type DataStore struct {
session *mgo.Session
}
func (ds *DataStore) ucol() *mgo.Collection { ... }
func (ds *DataStore) UserExist(user string) bool { ... }
Hay muchos beneficios en ese diseño. Una importante es que le permite tener varias sesiones en vuelo al mismo tiempo, por lo que si tiene un controlador http, por ejemplo, puede crear una sesión local respaldada por una sesión independiente solo para esa solicitud:
func (s *WebSite) dataStore() *DataStore {
return &DataStore{s.session.Copy()}
}
func (s *WebSite) HandleRequest(...) {
ds := s.dataStore()
defer ds.Close()
...
}
El controlador mgo se comporta bien en ese caso, ya que las sesiones se almacenan en caché internamente y se reutilizan / mantienen. Cada sesión también estará respaldada por un socket independiente mientras está en uso, y puede tener configuraciones independientes configuradas, y también tendrá un manejo de errores independiente. Estos son problemas que eventualmente tendrá que enfrentar si está usando una sola sesión global.