'How to properly disconnect MongoDB client
As far as I understand, you have to disconnect from MongoDB after you finish using it, but I'm not entirely sure how to do it right
var collection *mongo.Collection
var ctx = context.TODO()
func init() {
clientOptions := options.Client().ApplyURI("mongodb://localhost:27017/")
client, err := mongo.Connect(ctx, clientOptions)
if err != nil {
log.Fatal(err)
}
//defer client.Disconnect(ctx)
err = client.Ping(ctx, nil)
if err != nil {
log.Fatal(err)
}
fmt.Println("Connected successfully")
collection = client.Database("testDB").Collection("testCollection") //create DB
}
There is commented out function call
defer client.Disconnect(ctx)
Which would work fine if all code happens in main() function, but since defer gets called right after init() executes, DB in main() function is already disconnected.
So the question is - what would be the right way to approach this case?
Solution 1:[1]
Your application needs the connected MongoDB client in your all services or repositories and therefore it is easier, if you have separated MongoDB client connect and disconnect functions in application package. You don't need to connect MongoDB client, if your server is starting, you can connect first if your services or repositories need the MongoDB client connection.
// db.go
package application
import (
"context"
"fmt"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
"log"
"os"
)
var client *mongo.Client
func ResolveClientDB() *mongo.Client {
if client != nil {
return client
}
var err error
// TODO add to your .env.yml or .config.yml MONGODB_URI: mongodb://localhost:27017
clientOptions := options.Client().ApplyURI(os.Getenv("MONGODB_URI"))
client, err = mongo.Connect(context.Background(), clientOptions)
if err != nil {
log.Fatal(err)
}
// check the connection
err = client.Ping(context.Background(), nil)
if err != nil {
log.Fatal(err)
}
// TODO optional you can log your connected MongoDB client
return client
}
func CloseClientDB() {
if client == nil {
return
}
err := client.Disconnect(context.TODO())
if err != nil {
log.Fatal(err)
}
// TODO optional you can log your closed MongoDB client
fmt.Println("Connection to MongoDB closed.")
}
In main:
func main() {
// TODO add your main code here
defer application.CloseClientDB()
}
In your repositories or services you can get now your MongoDB client easily:
// account_repository.go
// TODO add here your account repository interface
func (repository *accountRepository) getClient() *mongo.Client {
if repository.client != nil {
return repository.client
}
repository.client = application.ResolveClientDB()
return repository.client
}
func (repository *accountRepository) FindOneByFilter(filter bson.D) (*model.Account, error) {
var account *model.Account
collection := repository.getClient().Database("yourDB").Collection("account")
err := collection.FindOne(context.Background(), filter).Decode(&account)
return account, err
}
Solution 2:[2]
The best way to do this in Python is to write your database connection as a singleton and then use the 'atexit' module to to decorate a function that disconnects. This ensures the connection is only instantiated once as we don't want to open multiple connections as we want to share one as well as at the end of your program the connection is disconnected.
import atexit
from pymongo import MongoClient
class MongoDB:
'''define class attributes'''
__instance = None
@staticmethod
def getInstance():
""" Static access method. """
# if the instance doesnt exist envoke the constructor
if MongoDB.__instance == None:
MongoDB()
# return instance
return MongoDB.__instance
def __init__(self) -> None:
""" Virtually private constructor. """
if MongoDB.__instance != None:
raise Exception("Singleton cannot be instantiated more than once")
else:
print("Creating MongoDB connection")
# set instance and instance attributes
self.client = MongoClient(config.CONNECTION_STRING)
MongoDB.__instance = self
@staticmethod
@atexit.register
def closeConnection():
'''
Python '__del__' aka destructor dunder doesnt always get called
mainly when program is terminated by ctrl-c so this method is decorated
by 'atexit' which ensures this method is called upon program termination
'''
if MongoDB.__instance != None:
MongoDB.__instance.client.close()
print("Closing Connections")
If anyone knows of a better design pattern feel free to comment this is just something I came up with that seems to work well.
Hope this helps
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Cem Ikta |
| Solution 2 | syntactic |
