Search code examples
mongodbgomgo

Golang / MGO -- panic: no reachable servers


I have the following function that connects to Mongo. For testing, I shutdown mongod, and want to allow the program to continue w/0 mongo if it's not available. It seems that MGO throws a panic if the server can't be connected, so I wrote a defer/recover below, but the panic still causes the program to exit. What's the proper way to recover from this?

func connectToMongo(sess *mgo.Session, coll *mgo.Collection, sessionErr error) bool {
    fmt.Println("enter main - connecting to mongo")

    // tried doing this - doesn't work as intended
    defer func() {
        if r := recover(); r != nil {
            var ok bool
            err, ok := r.(error)
            if !ok {
                fmt.Printf("pkg:  %v,  error: %s", r, err)
            }
        }
        return false
    }()

    maxWait := time.Duration(5 * time.Second)
    sess, sessionErr = mgo.DialWithTimeout("localhost", maxWait)
    if sessionErr == nil {
        session.SetMode(mgo.Monotonic, true)
        coll = session.DB("MyDB").C("MyCollection")
    } else { // never gets here
        fmt.Println("Unable to connect to local mongo instance!")
    }
    return true
}

Solution

  • Run the following version of your posted code. Try to not modify the code, at least not changing the position of the line numbers. That way, if you post a stacktrace, the numbers will match.

    package main
    
    import (
        "fmt"
        "time"
    )
    
    import (
        "labix.org/v2/mgo"
    )
    
    func connectToMongo() bool {
        ret := false
        fmt.Println("enter main - connecting to mongo")
    
        // tried doing this - doesn't work as intended
        defer func() {
            if r := recover(); r != nil {
                fmt.Println("Detected panic")
                var ok bool
                err, ok := r.(error)
                if !ok {
                    fmt.Printf("pkg:  %v,  error: %s", r, err)
                }
            }
        }()
    
        maxWait := time.Duration(5 * time.Second)
        session, sessionErr := mgo.DialWithTimeout("localhost:27017", maxWait)
        if sessionErr == nil {
            session.SetMode(mgo.Monotonic, true)
            coll := session.DB("MyDB").C("MyCollection")
            if ( coll != nil ) {
                fmt.Println("Got a collection object")
                ret = true
            }
        } else { // never gets here
            fmt.Println("Unable to connect to local mongo instance!")
        }
        return ret
    }
    
    func main() {
        if ( connectToMongo() ) {
            fmt.Println("Connected")
        } else {
            fmt.Println("Not Connected")
        }
    }
    

    When MongoDB is up, I see:

    enter main - connecting to mongo
    Got a collection object
    Connected
    

    When MongoDB is down, I see:

    enter main - connecting to mongo
    Unable to connect to local mongo instance!
    Not Connected
    

    If you don't see the same behavior, post the output, including the panic you see.