0

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
}
ANisus
  • 74,460
  • 29
  • 162
  • 158
user2644113
  • 1,101
  • 3
  • 16
  • 24
  • Not able to recreate your error. `mgo.DialWithTimeout` just returns an error, `no reachable servers`, instead of panicing. Please include import path of `mgo` (version) and panic message (what line that panics) – ANisus Jan 07 '14 at 17:39
  • Bear in mind that "If the deferred function has any return values, they are discarded when the function completes." If you want to modify/provide the return value you will need to use named return values as described here: "...if the deferred function is a function literal and the surrounding function has named result parameters that are in scope within the literal, the deferred function may access and modify the result parameters before they are returned." – Dmitri Goldring Jan 07 '14 at 17:52

1 Answers1

4

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.

Daniel Coupal
  • 815
  • 6
  • 8