ThreeAccents
ThreeAccents

Reputation: 1882

Concurrently using the same mgo session in go

So I'm having some trouble figuring out best practices for using concurrency with a MongoDB in go. My first implementation of getting a session looked like this:

var globalSession *mgo.Session

func getSession() (*mgo.Session, error) {
    //Establish our database connection
    if globalSession == nil {
        var err error
        globalSession, err = mgo.Dial(":27017")
        if err != nil {
            return nil, err
        }

        //Optional. Switch the session to a monotonic behavior.
        globalSession.SetMode(mgo.Monotonic, true)
    }

    return globalSession.Copy(), nil
}

This works great the trouble I'm running into is that mongo has a limit of 204 connections then it starts refusing connections connection refused because too many open connections: 204;however, the issue is since I'm calling session.Copy() it only returns a session and not an error. So event though the connection refused my program never thrown an error.

Now what I though about doing is just having one session and using that instead of copy so I can have access to a connection error like so:

var session *mgo.Session = nil

func NewSession() (*mgo.Session, error) {
    if session == nil {
        session, err = mgo.Dial(url)
        if err != nil {
            return nil, err
        }
    }

    return session, nil
}

Now the problem I have with this is that I don't know what would happen if I try to make concurrent usage of that same session.

Upvotes: 2

Views: 1414

Answers (1)

Aidan Ewen
Aidan Ewen

Reputation: 13308

The key is to duplicate the session and then close it when you've finished with it.

func GetMyData() []myMongoDoc {

    sessionCopy, _ := getSession() // from the question above
    defer sessionCopy.Close() // this is the important bit

    results := make([]myMongoDoc, 0)
    sessionCopy.DB("myDB").C("myCollection").Find(nil).All(&results)
    return results
}

Having said that it looks like mgo doesn't actually expose control over the underlying connections (see the comment from Gustavo Niemeyer who maintains the library). A session pretty much equates to a connection, but even if you call Close() on a session mgo keeps the connection alive. From reading around it seems that Clone() might be the way to go, as it reuses the underlying socket, this will avoid the 3 way handshake of creating a new socket (see here for more discussion on the difference).

Also see this SO answer describing a standard pattern to handle sessions.

Upvotes: 1

Related Questions