Best practice to maintain a mgo session

后端 未结 3 881
感动是毒
感动是毒 2020-11-27 14:03

I\'m currently using a mongodb with mgo lib for a web application, but I\'m not sure if the way I\'m using it, is good one ..

package db

import (
    \"gopk         


        
相关标签:
3条回答
  • 2020-11-27 14:43

    Although not directly answering your question, regarding mgo session checking you must use defer/recover since mgo calls (even mgo.session.Ping) panic. As far as I can tell there is no other way of checking mgo session state (mgo godocs). You can use Gustavo Niemeyer's suggestion and add a method on your DataStore type.

    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 讨论(0)
  • 2020-11-27 14:54

    With go 1.7, the most idiomatic way of handling mongo session on a webserver is to use the new standard library package context to write a middleware that can attach the defer session.Close() to whenever the request context Done() is called. So you do not need to remeber to close

    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 讨论(0)
  • 2020-11-27 15:08

    I suggest not using a global session like that. Instead, you can create a type that is responsible for all the database interaction. For example:

    type DataStore struct {
        session *mgo.Session
    }
    
    func (ds *DataStore) ucol() *mgo.Collection { ... }
    
    func (ds *DataStore) UserExist(user string) bool { ... }
    

    There are many benefits to that design. An important one is that it allows you to have multiple sessions in flight at the same time, so if you have an http handler, for example, you can create a local session that is backed by an independent session just for that one request:

    func (s *WebSite) dataStore() *DataStore {
        return &DataStore{s.session.Copy()}
    }    
    
    func (s *WebSite) HandleRequest(...) {
        ds := s.dataStore()
        defer ds.Close()
        ...
    }
    

    The mgo driver behaves nicely in that case, as sessions are internally cached and reused/maintained. Each session will also be backed by an independent socket while in use, and may have independent settings configured, and will also have independent error handling. These are issues you'll eventually have to deal with if you're using a single global session.

    0 讨论(0)
提交回复
热议问题