Skip to main content

Command Palette

Search for a command to run...

Notes: Go Design Patterns - Singleton Pattern

This blog contains Singleton design pattern implementation by creating exactly one MongoDB connection

Published
2 min read
Notes: Go Design Patterns - Singleton Pattern

Singleton pattern makes sure that only one instance of an object is created. This pattern is used to create DB connections or connections with other external systems. We'll see its usage by trying to create a singleton MongoDB connection:

func getNewMongoClient() *mongo.Client {
    if mongoClient == nil {
        once.Do(
            mongoConnect,
        )
    } else {
        fmt.Println("mongo client already created.")
    }

    return mongoClient
}

Here once.Do makes sure that this section of the code gets executed only one time no matter how many times it is called. We could have used mutex locks as well but the right way to implement a singleton pattern in Go is to use the sync package’s Once.Do function. This function makes sure that your specified code is executed only once and never more than once.

To run the example code, first, start a mongo server using docker: docker run -d -p 27017:27017 --name mongo-server mongo:latest

Now, once you run this code, you'll see that only the first getNewMongoClient() will return success while subsequent calls will fail.

Working code to test:

package main

import (
    "context"
    "fmt"
    "log"
    "sync"

    "go.mongodb.org/mongo-driver/mongo"
    "go.mongodb.org/mongo-driver/mongo/options"
)

var once sync.Once

var mongoClient *mongo.Client

// start mongo server by using this command:
// docker run -d -p 27017:27017 --name mongo-server mongo:latest
func mongoConnect() {
    var err error

    // Set client options
    clientOptions := options.Client().ApplyURI("mongodb://localhost:27017")

    // Connect to MongoDB
    mongoClient, err = mongo.Connect(context.TODO(), clientOptions)

    if err != nil {
        log.Fatal(err)
    }

    // Check the connection
    err = mongoClient.Ping(context.TODO(), nil)

    if err != nil {
        log.Fatal(err)
    }

    fmt.Println("connected to mongo!")
}

func getNewMongoClient() *mongo.Client {
    if mongoClient == nil {
        once.Do(
            mongoConnect,
        )
    } else {
        fmt.Println("mongo client already created.")
    }

    return mongoClient
}

func main() {
    getNewMongoClient()
    getNewMongoClient()
    getNewMongoClient()
    getNewMongoClient()
}

More from this blog

btree.dev

28 posts

Hey 👋 , I am a Backend Engineer working at Getir. In this blog, I write about software architecture, distributed systems, and other interesting computer science concepts.