web-dev-qa-db-fra.com

Meilleure pratique pour maintenir une session mgo

J'utilise actuellement mongodb avec mgo lib pour une application Web, mais je ne suis pas sûr que je l'utilise de la bonne façon.

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

J'ouvre la session de base de données et crée des variables qui prennent la collection et la valeur du document, Ainsi, lorsque je dois interroger une collection, j'utilise la variable pour la créer.

Comme ça :

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
    }
}

Alors, y a-t-il une meilleure pratique ou celle-ci va bien ...? Merci

25
JonathanChaput

Je suggère de ne pas utiliser une session globale comme ça. Au lieu de cela, vous pouvez créer un type responsable de toutes les interactions avec la base de données. Par exemple:

type DataStore struct {
    session *mgo.Session
}

func (ds *DataStore) ucol() *mgo.Collection { ... }

func (ds *DataStore) UserExist(user string) bool { ... }

Cette conception présente de nombreux avantages. Un point important est qu'il vous permet d'avoir plusieurs sessions en vol en même temps. Ainsi, si vous avez un gestionnaire http, par exemple, vous pouvez créer une session locale qui est sauvegardée par une session indépendante uniquement pour cette requête:

func (s *WebSite) dataStore() *DataStore {
    return &DataStore{s.session.Copy()}
}    

func (s *WebSite) HandleRequest(...) {
    ds := s.dataStore()
    defer ds.Close()
    ...
}

Le pilote mgo se comporte bien dans ce cas, car les sessions sont mises en cache en interne et réutilisées/maintenues. Chaque session sera également sauvegardée par un socket indépendant lors de son utilisation, et pourra avoir des paramètres indépendants configurés, ainsi qu'un traitement des erreurs indépendant. Ce sont des problèmes que vous devrez éventuellement traiter si vous utilisez une seule session globale.

62
Gustavo Niemeyer

Bien que ne répondant pas directement à votre question, en ce qui concerne la vérification de session mgo, vous devez utiliser différer/récupérer car les appels mgo (même mgo.session.Ping) paniquent. Autant que je sache, il n’ya pas d’autre moyen de vérifier l’état de la session mgo ( mgo godocs ). Vous pouvez utiliser la suggestion de Gustavo Niemeyer et ajouter une méthode à votre type 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()
}
2
Zamicol

Avec go 1.7, le moyen le plus idiomatique de gérer une session Mongo sur un serveur Web consiste à utiliser le nouveau package de bibliothèque standard context pour écrire un middleware pouvant associer la fonction defer session.Close() à chaque appel du contexte de requête Done (). Donc, vous n'avez pas besoin de vous rappeler de fermer

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))
        })
    }
0
CESCO