What is the best practice for handling scope with dealing with shared connection resources to outside services in golang (RabbitMQ, database, etc)? For example, given this code using database/sql, pq, and http:
func main() {
db, err := sql.Open("postgres", "user=root dbname=root")
if err != nil {
log.Fatal(err)
}
http.HandleFunc("/", front_handler)
http.HandleFunc("/get", get_handler)
http.HandleFunc("/set", set_handler)
http.ListenAndServe(":8080", nil)
}
What's the best way to make the db
object available to my registered handlers?
Do I put the db
declaration outside the main scope (this would cause me unit testing problems in Python but might be okay here)?
Do I put the handler declarations inside the main scope (it doesn't seem like I'm allowed to nest functions)?
Is there an addressing scheme I can use to access the main scope (I'd do something like that in puppet)?
Some other option?
There's a lot of ways you could deal with this. Firstly, having opened the connection in this scope, you probably want to defer it's close here.
db, err := sql.Open("postgres", "user=root dbname=root")
if err != nil {
log.Fatal(err)
}
defer db.Close()
Which will ensure the connection gets cleaned up when you're leaving this scope. Regarding your handlers... It would be simple to write them as closures in the same scope as the connection so you can use it freely.
EDIT: To clarify, you said you don't think you can nest functions in main. You can do this with something like;
get_handler := func() {
return db.ReadTheData()
}
http.HandleFunc("get", get_handler)
It's common for most apps to start out with the DB handler at the global scope. sql.DB
is defined to be safe for concurrent access, and therefor can be simultaneously used by all handlers that need it.
var db *sql.DB
func main() {
var err error
db, err = sql.Open("postgres", "user=root dbname=root")
if err != nil {
log.Fatal(err)
}
...