2014-10-26 11 views
23

Attualmente sto usando un MongoDB con MgO lib per un'applicazione web, ma non sono sicuro se il modo in cui lo sto usando, è buona ..Le migliori pratiche per mantenere una sessione di MgO

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

Iniziamo la sessione db e creo variabili che prendono il valore di raccolta e documento, così quando ho bisogno di interrogare una raccolta, io uso la variabile per renderla.

Come quella:

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

è così c'è una buona pratica o questo va bene ..? Grazie

+0

È consigliabile utilizzare una funzione per impostare la sessione del database rispetto alle dichiarazioni variabili. Un motivo per utilizzare una funzione è che è possibile gestire il ritorno dell'errore da Dial. Per UserExist, utilizzerei il [numero di documenti nel set di risultati] (http://godoc.org/gopkg.in/mgo.v2#Query.Count) per determinare se esiste un documento. Non è necessario recuperare il documento vero e proprio. –

+0

grazie per il suggerimento per la funzione UserExist! Ma con la funzione per avviare la connessione di sessione, posso farlo con "func init()" nel pacchetto db e assegnare la variabile globale per db e collection con la sessione di ritorno? Non sono sicuro di come mantenere la mia sessione con il db open, senza creare un "mgo.Dial()" ogni volta che ne ho bisogno, e ho anche il mio db e la raccolta già inizializzati ... – JonathanChaput

risposta

47

Suggerisco di non utilizzare una sessione globale come quella. Invece, è possibile creare un tipo responsabile di tutte le interazioni del database. Ad esempio:

type DataStore struct { 
    session *mgo.Session 
} 

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

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

Ci sono molti vantaggi a questo progetto. Un aspetto importante è che consente di avere più sessioni in volo contemporaneamente, quindi se si dispone di un gestore HTTP, ad esempio, è possibile creare una sessione locale supportata da una sessione indipendente solo per quella richiesta:

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

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

Il driver mgo si comporta bene in questo caso, poiché le sessioni vengono memorizzate nella cache e riutilizzate/mantenute. Ogni sessione sarà inoltre supportata da un socket indipendente mentre è in uso e potrebbe avere impostazioni indipendenti configurate e avrà anche una gestione degli errori indipendente. Questi sono problemi che dovrai affrontare se stai utilizzando un'unica sessione globale.

+10

Ci sono _many_ ragioni per avere questa configurazione come hai dichiarato. La chiamata 'session.Copy()' è particolarmente importante e qualcosa che non è abbastanza stressato per le persone che utilizzano il driver Mongo in Go, dato che consente al driver di sfruttare appieno la concorrenza. Ma allora - sai tutto di questo ..: P +1 –

+0

Quindi fai ruotare una sessione globale iniziale e poi la copi su ogni richiesta? – collinglass

+1

Una sessione principale, sì. Non deve essere globale nel senso della "variabile globale" della parola. –

2

Sebbene non risponda direttamente alla domanda, per quanto riguarda il controllo della sessione di mgo è necessario utilizzare il rinvio/recupero dal momento che il mico chiama (anche mgo.session.Ping) il panico. Per quanto posso dire non c'è altro modo per controllare lo stato della sessione di mgo (mgo godocs). Puoi utilizzare il suggerimento di Gustavo Niemeyer e aggiungere un metodo al tuo tipo 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() 
} 
+0

È possibile ripristinare i gestori con un middleware di ripristino senza questo. –

+0

@inanc Come si ottiene il middleware? DataStore.Ping? – Zamicol

+0

In caso di panico, controlla il messaggio di errore e quindi riconnettiti. –

1

con Go 1.7, il modo più idiomatico di gestire sessione di Mongo su un server web è quello di utilizzare il nuovo pacchetto di libreria standard context per scrivere un middleware in grado di attaccare il defer session.Close() per ogni volta che il contesto di richiesta Done() viene chiamato . Quindi non è necessario ricordare per chiudere

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)) 
     }) 
    } 
+2

Il contesto non è pensato per le cose di lunga durata come le sessioni di mongo. Questo è un anti-pattern puzzolente. –

+0

@InancGumus Quale metodo è il modo migliore per gestire la sessione mongo? Sto vedendo alcuni esempi sull'uso del contesto e delle sessioni di mongo. – UnNatural

+0

È sufficiente copiare la sessione da un membro della struttura immesso, ad esempio lungo la linea. –

Problemi correlati