From f97bea78eb81f71c609f57101cd1645799154646 Mon Sep 17 00:00:00 2001 From: Fred Boniface Date: Sun, 14 Apr 2024 21:21:13 +0100 Subject: [PATCH] Added multiple attempts with backoff delay to datebase connection --- dbAccess/client.go | 48 ++++++++++++++++++++++++++++++++++------------ helpers/backoff.go | 18 +++++++++++++++++ 2 files changed, 54 insertions(+), 12 deletions(-) create mode 100644 helpers/backoff.go diff --git a/dbAccess/client.go b/dbAccess/client.go index 3f566f4..56a8aac 100644 --- a/dbAccess/client.go +++ b/dbAccess/client.go @@ -3,9 +3,9 @@ package dbAccess import ( "git.fjla.uk/owlboard/timetable-mgr/helpers" "git.fjla.uk/owlboard/timetable-mgr/log" + "go.uber.org/zap" "context" - "fmt" "time" "go.mongodb.org/mongo-driver/mongo" @@ -26,19 +26,43 @@ var bsonOpts = &options.BSONOptions{ UseJSONStructTags: true, } -// Initialise the DB Connection func InitDataAccess(cfg *helpers.Configuration) { - uri := getDbUri(cfg) - ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) - defer cancel() - client, err := mongo.Connect(ctx, options.Client().ApplyURI(uri).SetBSONOptions(bsonOpts)) - if err != nil { - fmt.Println(err) - log.Fatal("Error connecting to database: " + err.Error()) - } else { - log.Info("Database connection initialising") + log.Debug("Starting database connection") + url := getDbUri(cfg) + + const maxRetries = 8 + + for attempt := 1; attempt <= maxRetries; attempt++ { + log.Info("Attempting to connect to database", zap.Int("attempt", attempt), zap.Int("max-tries", maxRetries)) + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + + client, err := mongo.Connect(ctx, options.Client().ApplyURI(url).SetBSONOptions(bsonOpts)) + if err != nil { + log.Warn("Error connecting to database", zap.Int("attempt", attempt), zap.Int("max-tries", maxRetries)) + cancel() + if attempt != maxRetries { + helpers.BackoffDelay(attempt) + } + continue + } + + err = client.Ping(ctx, nil) + if err != nil { + log.Warn("Error pinging database", zap.Int("attempt", attempt), zap.Int("max-tries", maxRetries)) + cancel() + if attempt != maxRetries { + helpers.BackoffDelay(attempt) + } + continue + } + + MongoClient = client + log.Info("Database connection successful") + return } - MongoClient = client + + log.Fatal("Failed to connect to database on multiple attempts", zap.Int("attempts", maxRetries)) } // Closes the connection to the database - used for cleanup functions diff --git a/helpers/backoff.go b/helpers/backoff.go new file mode 100644 index 0000000..403bddd --- /dev/null +++ b/helpers/backoff.go @@ -0,0 +1,18 @@ +package helpers + +import ( + "math" + "time" + + "git.fjla.uk/owlboard/timetable-mgr/log" + "go.uber.org/zap" +) + +// Implements an exponential backoff strategy and sleeps for a duration calculated as 1 second to the power of (attempt - 1). +// The backoff time doubles with each attempt, starting from 1 second for the first attempt. +func BackoffDelay(attempt int) { + base := time.Second + backoff := base * time.Duration(math.Pow(2, float64(attempt-1))) + log.Info("Retry backoff", zap.Duration("delay", backoff)) + time.Sleep(backoff) +}