0
\$\begingroup\$

Created a MongoDB client which is handling the retry in case of server connection failure. Please review and how I can improve further.

package db

import (
    "context"
    "errors"
    "log"
    "time"
    

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

const SupplyReportDB = "abc"
const SupplyAlertsCollection = "abc"

type MongoDB struct {
    client *mongo.Client
    uri    string
}

func NewMongoDBCon(context context.Context, uri string) (*MongoDB, error) {
    var conn = &MongoDB{uri: uri}
    client, err := conn.Connect(context)
    if err != nil {
        return conn, err
    }
    conn.client = client
    return conn, err
}

func (m *MongoDB) Connect(context context.Context) (*mongo.Client, error) {
    serverMonitor := &event.ServerMonitor{
        ServerHeartbeatFailed: m.serverHandler,         
    }

    client, err := mongo.Connect(
        context, options.Client().
            ApplyURI(m.uri).
            SetHeartbeatInterval(5*time.Second).
            SetServerMonitor(serverMonitor),
    )

    if err != nil {
        return client, err
    }

    if err := client.Ping(context, nil); err != nil {
        return client, errors.New("not connected")
    }
    return client, nil
}

func (m *MongoDB) Close(context context.Context) error {
    if err := m.client.Disconnect(context); err != nil {
        return err
    }
    return nil
}

func (m *MongoDB) GetSupplyAlertCollection() *mongo.Collection {
    collection := m.client.Database(SupplyReportDB).Collection(SupplyAlertsCollection)
    return collection
}

func (m *MongoDB) reconnect() {
    count := 1
    for {
        if count == 3{
            log.Fatal("Problem in connecting MongoDB.. exiting..")
        }
        log.Println("Retrying for the ", count, "time")
        client, err := m.Connect(context.TODO())
        if err != nil {
            time.Sleep(4 * time.Second)
        } else {
            log.Println("Reconnected successfully.")
            m.client = client
            break
        }
        count++
    }
}

func (m *MongoDB)serverHandler(evt *event.ServerHeartbeatFailedEvent) {
    m.reconnect()   
}
\$\endgroup\$

1 Answer 1

2
\$\begingroup\$

I would think about replacing the "for loop" with a retry package https://github.com/avast/retry-go. Should be a little bit cleaner.

func (m *MongoDB) reconnect() {
err := retry.Do(func() error {
    client, err := mongo.Connect(context.TODO(), m.uri, mongo.ConnectTimeout(5*time.Second))
    if err != nil {
        log.Printf("Failed to connect to MongoDB at %s: %s", m.uri, err)
        return err
    }
    log.Println("Reconnected successfully.")
    m.client = client
    return nil
},
    retry.Attempts(3),
    retry.Delay(4*time.Second),
    retry.OnRetry(func(n uint, err error) {
        log.Printf("Retry %d: %s", n, err)
    }),
)
if err != nil {
    log.Fatal("Problem in connecting MongoDB.. exiting..")
}}

Also using exponential backoff (in the delay) could be an option.

\$\endgroup\$

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.