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\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.